From 4f5109983b81bc6a4289c40d9e2bdbe599e97054 Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Fri, 2 Jul 2021 21:08:10 -0400 Subject: [PATCH 01/14] feat(Managers): add customizable cache --- src/client/BaseClient.js | 4 +- src/client/Client.js | 12 +- src/index.js | 1 + src/managers/ApplicationCommandManager.js | 8 +- .../ApplicationCommandPermissionsManager.js | 14 +- src/managers/BaseGuildEmojiManager.js | 8 +- src/managers/BaseManager.js | 66 +------- src/managers/CachedManager.js | 43 +++++ src/managers/ChannelManager.js | 8 +- src/managers/DataManager.js | 64 ++++++++ src/managers/GuildBanManager.js | 8 +- src/managers/GuildChannelManager.js | 8 +- src/managers/GuildEmojiRoleManager.js | 13 +- src/managers/GuildManager.js | 8 +- src/managers/GuildMemberManager.js | 9 +- src/managers/GuildMemberRoleManager.js | 13 +- src/managers/MessageManager.js | 10 +- src/managers/PermissionOverwriteManager.js | 8 +- src/managers/PresenceManager.js | 8 +- src/managers/ReactionManager.js | 8 +- src/managers/ReactionUserManager.js | 11 +- src/managers/RoleManager.js | 9 +- src/managers/StageInstanceManager.js | 8 +- src/managers/ThreadManager.js | 8 +- src/managers/ThreadMemberManager.js | 11 +- src/managers/UserManager.js | 8 +- src/managers/VoiceStateManager.js | 9 +- src/structures/MessageReaction.js | 3 +- src/util/Constants.js | 111 ------------- src/util/Options.js | 154 ++++++++++++++++++ src/util/Util.js | 6 +- test/tester2000.js | 57 +++++++ typings/index.d.ts | 82 ++++++---- typings/index.ts | 4 + 34 files changed, 486 insertions(+), 316 deletions(-) create mode 100644 src/managers/CachedManager.js create mode 100644 src/managers/DataManager.js create mode 100644 src/util/Options.js create mode 100644 test/tester2000.js diff --git a/src/client/BaseClient.js b/src/client/BaseClient.js index bf3f3b9c81f6..ad9f26c35525 100644 --- a/src/client/BaseClient.js +++ b/src/client/BaseClient.js @@ -2,7 +2,7 @@ const EventEmitter = require('events'); const RESTManager = require('../rest/RESTManager'); -const { DefaultOptions } = require('../util/Constants'); +const Options = require('../util/Options'); const Util = require('../util/Util'); /** @@ -38,7 +38,7 @@ class BaseClient extends EventEmitter { * The options the client was instantiated with * @type {ClientOptions} */ - this.options = Util.mergeDefault(DefaultOptions, options); + this.options = Util.mergeDefault(Options.createDefaultOptions(), options); /** * The REST manager of the client diff --git a/src/client/Client.js b/src/client/Client.js index 3da2f439fc75..97b165def123 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -17,9 +17,10 @@ const VoiceRegion = require('../structures/VoiceRegion'); const Webhook = require('../structures/Webhook'); const Widget = require('../structures/Widget'); const Collection = require('../util/Collection'); -const { Events, DefaultOptions, InviteScopes } = require('../util/Constants'); +const { Events, InviteScopes } = require('../util/Constants'); const DataResolver = require('../util/DataResolver'); const Intents = require('../util/Intents'); +const Options = require('../util/Options'); const Permissions = require('../util/Permissions'); const Structures = require('../util/Structures'); @@ -35,14 +36,15 @@ class Client extends BaseClient { super(Object.assign({ _tokenType: 'Bot' }, options)); const data = require('worker_threads').workerData ?? process.env; + const defaults = Options.createDefaultOptions(); - if (this.options.shards === DefaultOptions.shards) { + if (this.options.shards === defaults.shards) { if ('SHARDS' in data) { this.options.shards = JSON.parse(data.SHARDS); } } - if (this.options.shardCount === DefaultOptions.shardCount) { + if (this.options.shardCount === defaults.shardCount) { if ('SHARD_COUNT' in data) { this.options.shardCount = Number(data.SHARD_COUNT); } else if (Array.isArray(this.options.shards)) { @@ -468,8 +470,8 @@ class Client extends BaseClient { throw new TypeError('CLIENT_INVALID_OPTION', 'shards', "'auto', a number or array of numbers"); } if (options.shards && !options.shards.length) throw new RangeError('CLIENT_INVALID_PROVIDED_SHARDS'); - if (typeof options.messageCacheMaxSize !== 'number' || isNaN(options.messageCacheMaxSize)) { - throw new TypeError('CLIENT_INVALID_OPTION', 'messageCacheMaxSize', 'a number'); + if (typeof options.makeCache !== 'function') { + throw new TypeError('CLIENT_INVALID_OPTION', 'makeCache', 'a function'); } if (typeof options.messageCacheLifetime !== 'number' || isNaN(options.messageCacheLifetime)) { throw new TypeError('CLIENT_INVALID_OPTION', 'The messageCacheLifetime', 'a number'); diff --git a/src/index.js b/src/index.js index 02aa7da1f0e7..2ccdff2749a5 100644 --- a/src/index.js +++ b/src/index.js @@ -23,6 +23,7 @@ module.exports = { RateLimitError: require('./rest/RateLimitError'), MessageFlags: require('./util/MessageFlags'), Intents: require('./util/Intents'), + Options: require('./util/Options'), Permissions: require('./util/Permissions'), SnowflakeUtil: require('./util/SnowflakeUtil'), Structures: require('./util/Structures'), diff --git a/src/managers/ApplicationCommandManager.js b/src/managers/ApplicationCommandManager.js index 864db7f090fd..6b47a29729f7 100644 --- a/src/managers/ApplicationCommandManager.js +++ b/src/managers/ApplicationCommandManager.js @@ -1,18 +1,18 @@ 'use strict'; const ApplicationCommandPermissionsManager = require('./ApplicationCommandPermissionsManager'); -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const { TypeError } = require('../errors'); const ApplicationCommand = require('../structures/ApplicationCommand'); const Collection = require('../util/Collection'); /** * Manages API methods for application commands and stores their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class ApplicationCommandManager extends BaseManager { +class ApplicationCommandManager extends CachedManager { constructor(client, iterable) { - super(client, iterable, ApplicationCommand); + super(client, ApplicationCommand, iterable); /** * The manager for permissions of arbitrary commands on arbitrary guilds diff --git a/src/managers/ApplicationCommandPermissionsManager.js b/src/managers/ApplicationCommandPermissionsManager.js index bf10454efb31..79643c11539f 100644 --- a/src/managers/ApplicationCommandPermissionsManager.js +++ b/src/managers/ApplicationCommandPermissionsManager.js @@ -1,14 +1,18 @@ 'use strict'; +const BaseManager = require('./BaseManager'); const { Error, TypeError } = require('../errors'); const Collection = require('../util/Collection'); const { ApplicationCommandPermissionTypes, APIErrors } = require('../util/Constants'); /** * Manages API methods for permissions of Application Commands. + * @extends {BaseManager} */ -class ApplicationCommandPermissionsManager { +class ApplicationCommandPermissionsManager extends BaseManager { constructor(manager) { + super(manager.client); + /** * The manager or command that this manager belongs to * @type {ApplicationCommandManager|ApplicationCommand} @@ -32,14 +36,6 @@ class ApplicationCommandPermissionsManager { * @type {?Snowflake} */ this.commandID = manager.id ?? null; - - /** - * The client that instantiated this Manager - * @name ApplicationCommandPermissionsManager#client - * @type {Client} - * @readonly - */ - Object.defineProperty(this, 'client', { value: manager.client }); } /** diff --git a/src/managers/BaseGuildEmojiManager.js b/src/managers/BaseGuildEmojiManager.js index dad3e7368b02..5a39a2bfea1d 100644 --- a/src/managers/BaseGuildEmojiManager.js +++ b/src/managers/BaseGuildEmojiManager.js @@ -1,17 +1,17 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const GuildEmoji = require('../structures/GuildEmoji'); const ReactionEmoji = require('../structures/ReactionEmoji'); const { parseEmoji } = require('../util/Util'); /** * Holds methods to resolve GuildEmojis and stores their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class BaseGuildEmojiManager extends BaseManager { +class BaseGuildEmojiManager extends CachedManager { constructor(client, iterable) { - super(client, iterable, GuildEmoji); + super(client, GuildEmoji, iterable); } /** diff --git a/src/managers/BaseManager.js b/src/managers/BaseManager.js index ee326386910d..06514011a1a1 100644 --- a/src/managers/BaseManager.js +++ b/src/managers/BaseManager.js @@ -1,24 +1,11 @@ 'use strict'; -const Collection = require('../util/Collection'); -let Structures; - /** - * Manages the API methods of a data model and holds its cache. + * Manages the API methods of a data model. * @abstract */ class BaseManager { - constructor(client, iterable, holds, cacheType = Collection, ...cacheOptions) { - if (!Structures) Structures = require('../util/Structures'); - /** - * The data structure belonging to this manager - * @name BaseManager#holds - * @type {Function} - * @private - * @readonly - */ - Object.defineProperty(this, 'holds', { value: Structures.get(holds.name) ?? holds }); - + constructor(client) { /** * The client that instantiated this Manager * @name BaseManager#client @@ -26,55 +13,6 @@ class BaseManager { * @readonly */ Object.defineProperty(this, 'client', { value: client }); - - /** - * The type of Collection of the Manager - * @type {Collection} - */ - this.cacheType = cacheType; - - /** - * Holds the cache for the data model - * @type {Collection} - */ - this.cache = new cacheType(...cacheOptions); - if (iterable) for (const i of iterable) this.add(i); - } - - add(data, cache = true, { id, extras = [] } = {}) { - const existing = this.cache.get(id ?? data.id); - if (cache) existing?._patch(data); - if (existing) return existing; - - const entry = this.holds ? new this.holds(this.client, data, ...extras) : data; - if (cache) this.cache.set(id ?? entry.id, entry); - return entry; - } - - /** - * Resolves a data entry to a data Object. - * @param {string|Object} idOrInstance The id or instance of something in this Manager - * @returns {?Object} An instance from this Manager - */ - resolve(idOrInstance) { - if (idOrInstance instanceof this.holds) return idOrInstance; - if (typeof idOrInstance === 'string') return this.cache.get(idOrInstance) ?? null; - return null; - } - - /** - * Resolves a data entry to an instance ID. - * @param {string|Object} idOrInstance The id or instance of something in this Manager - * @returns {?Snowflake} - */ - resolveID(idOrInstance) { - if (idOrInstance instanceof this.holds) return idOrInstance.id; - if (typeof idOrInstance === 'string') return idOrInstance; - return null; - } - - valueOf() { - return this.cache; } } diff --git a/src/managers/CachedManager.js b/src/managers/CachedManager.js new file mode 100644 index 000000000000..8552bac467fa --- /dev/null +++ b/src/managers/CachedManager.js @@ -0,0 +1,43 @@ +'use strict'; + +const DataManager = require('./DataManager'); + +/** + * Manager that holds a cache. + * @extends {DataManager} + * @abstract + */ +class CachedManager extends DataManager { + constructor(client, holds, iterable) { + super(client, holds); + + Object.defineProperty(this, '_cache', { value: this.client.options.makeCache(this.holds) }); + + if (iterable) { + for (const item of iterable) { + this.add(item); + } + } + } + + /** + * The cache of items for this manager. + * @type {Collection} + * @abstract + */ + get cache() { + return this._cache; + } + + add(data, cache = true, { id, extras = [] } = {}) { + const existing = this.cache.get(id ?? data.id); + if (cache) existing?._patch(data); + if (existing) return existing; + + const entry = this.holds ? new this.holds(this.client, data, ...extras) : data; + if (cache) this.cache.set(id ?? entry.id, entry); + return entry; + } +} + +module.exports = CachedManager; diff --git a/src/managers/ChannelManager.js b/src/managers/ChannelManager.js index 953cea454b49..e4e94fddc167 100644 --- a/src/managers/ChannelManager.js +++ b/src/managers/ChannelManager.js @@ -1,16 +1,16 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const Channel = require('../structures/Channel'); const { Events, ThreadChannelTypes } = require('../util/Constants'); /** * A manager of channels belonging to a client - * @extends {BaseManager} + * @extends {CachedManager} */ -class ChannelManager extends BaseManager { +class ChannelManager extends CachedManager { constructor(client, iterable) { - super(client, iterable, Channel); + super(client, Channel, iterable); } /** diff --git a/src/managers/DataManager.js b/src/managers/DataManager.js new file mode 100644 index 000000000000..bbb09c21e7c3 --- /dev/null +++ b/src/managers/DataManager.js @@ -0,0 +1,64 @@ +'use strict'; + +const BaseManager = require('./BaseManager'); + +let Structures; + +/** + * Manager that holds data structures. + * @extends {BaseManager} + * @abstract + */ +class DataManager extends BaseManager { + constructor(client, holds) { + super(client); + + if (!Structures) Structures = require('../util/Structures'); + + /** + * The data structure belonging to this manager. + * @name BaseManager#holds + * @type {Function} + * @private + * @readonly + */ + Object.defineProperty(this, 'holds', { value: Structures.get(holds.name) ?? holds }); + } + + /** + * The cache of items for this manager. + * @type {Collection} + * @abstract + */ + get cache() { + throw new Error(`Getter 'cache' not implemented for ${this.constructor.name}`); + } + + /** + * Resolves a data entry to a data Object. + * @param {string|Object} idOrInstance The id or instance of something in this Manager + * @returns {?Object} An instance from this Manager + */ + resolve(idOrInstance) { + if (idOrInstance instanceof this.holds) return idOrInstance; + if (typeof idOrInstance === 'string') return this.cache.get(idOrInstance) ?? null; + return null; + } + + /** + * Resolves a data entry to an instance ID. + * @param {string|Object} idOrInstance The id or instance of something in this Manager + * @returns {?Snowflake} + */ + resolveID(idOrInstance) { + if (idOrInstance instanceof this.holds) return idOrInstance.id; + if (typeof idOrInstance === 'string') return idOrInstance; + return null; + } + + valueOf() { + return this.cache; + } +} + +module.exports = DataManager; diff --git a/src/managers/GuildBanManager.js b/src/managers/GuildBanManager.js index 735aeeb5b1a3..b0e106045fd0 100644 --- a/src/managers/GuildBanManager.js +++ b/src/managers/GuildBanManager.js @@ -1,6 +1,6 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const { TypeError, Error } = require('../errors'); const GuildBan = require('../structures/GuildBan'); const GuildMember = require('../structures/GuildMember'); @@ -8,11 +8,11 @@ const Collection = require('../util/Collection'); /** * Manages API methods for GuildBans and stores their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class GuildBanManager extends BaseManager { +class GuildBanManager extends CachedManager { constructor(guild, iterable) { - super(guild.client, iterable, GuildBan); + super(guild.client, GuildBan, iterable); /** * The guild this Manager belongs to diff --git a/src/managers/GuildChannelManager.js b/src/managers/GuildChannelManager.js index d7c0601230bc..5f94495a5471 100644 --- a/src/managers/GuildChannelManager.js +++ b/src/managers/GuildChannelManager.js @@ -1,6 +1,6 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const GuildChannel = require('../structures/GuildChannel'); const PermissionOverwrites = require('../structures/PermissionOverwrites'); const ThreadChannel = require('../structures/ThreadChannel'); @@ -9,11 +9,11 @@ const { ChannelTypes, ThreadChannelTypes } = require('../util/Constants'); /** * Manages API methods for GuildChannels and stores their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class GuildChannelManager extends BaseManager { +class GuildChannelManager extends CachedManager { constructor(guild, iterable) { - super(guild.client, iterable, GuildChannel); + super(guild.client, GuildChannel, iterable); /** * The guild this Manager belongs to diff --git a/src/managers/GuildEmojiRoleManager.js b/src/managers/GuildEmojiRoleManager.js index 55cddec85998..3b4b8710471b 100644 --- a/src/managers/GuildEmojiRoleManager.js +++ b/src/managers/GuildEmojiRoleManager.js @@ -1,13 +1,18 @@ 'use strict'; +const DataManager = require('./DataManager'); const { TypeError } = require('../errors'); +const Role = require('../structures/Role'); const Collection = require('../util/Collection'); /** * Manages API methods for roles belonging to emojis and stores their cache. + * @extends {DataManager} */ -class GuildEmojiRoleManager { +class GuildEmojiRoleManager extends DataManager { constructor(emoji) { + super(emoji.client, Role); + /** * The emoji belonging to this manager * @type {GuildEmoji} @@ -18,12 +23,6 @@ class GuildEmojiRoleManager { * @type {Guild} */ this.guild = emoji.guild; - /** - * The client belonging to this manager - * @type {Client} - * @readonly - */ - Object.defineProperty(this, 'client', { value: emoji.client }); } /** diff --git a/src/managers/GuildManager.js b/src/managers/GuildManager.js index 86df25bd8429..0dbc75ba1c2f 100644 --- a/src/managers/GuildManager.js +++ b/src/managers/GuildManager.js @@ -1,6 +1,6 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const Guild = require('../structures/Guild'); const GuildChannel = require('../structures/GuildChannel'); const GuildEmoji = require('../structures/GuildEmoji'); @@ -23,11 +23,11 @@ const { resolveColor } = require('../util/Util'); /** * Manages API methods for Guilds and stores their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class GuildManager extends BaseManager { +class GuildManager extends CachedManager { constructor(client, iterable) { - super(client, iterable, Guild); + super(client, Guild, iterable); } /** diff --git a/src/managers/GuildMemberManager.js b/src/managers/GuildMemberManager.js index 629891a653cb..11bbb40e6152 100644 --- a/src/managers/GuildMemberManager.js +++ b/src/managers/GuildMemberManager.js @@ -1,6 +1,6 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const { Error, TypeError, RangeError } = require('../errors'); const BaseGuildVoiceChannel = require('../structures/BaseGuildVoiceChannel'); const GuildMember = require('../structures/GuildMember'); @@ -11,11 +11,12 @@ const SnowflakeUtil = require('../util/SnowflakeUtil'); /** * Manages API methods for GuildMembers and stores their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class GuildMemberManager extends BaseManager { +class GuildMemberManager extends CachedManager { constructor(guild, iterable) { - super(guild.client, iterable, GuildMember); + super(guild.client, GuildMember, iterable); + /** * The guild this manager belongs to * @type {Guild} diff --git a/src/managers/GuildMemberRoleManager.js b/src/managers/GuildMemberRoleManager.js index 1faa59e00ba1..90c13adf77f4 100644 --- a/src/managers/GuildMemberRoleManager.js +++ b/src/managers/GuildMemberRoleManager.js @@ -1,24 +1,29 @@ 'use strict'; +const DataManager = require('./DataManager'); const { TypeError } = require('../errors'); +const Role = require('../structures/Role'); const Collection = require('../util/Collection'); /** * Manages API methods for roles of a GuildMember and stores their cache. + * @extends {DataManager} */ -class GuildMemberRoleManager { +class GuildMemberRoleManager extends DataManager { constructor(member) { + super(member.client, Role); + /** * The GuildMember this manager belongs to * @type {GuildMember} */ this.member = member; + /** * The Guild this manager belongs to * @type {Guild} */ this.guild = member.guild; - Object.defineProperty(this, 'client', { value: member.client }); } /** @@ -170,10 +175,6 @@ class GuildMemberRoleManager { clone.member._roles = [...this.cache.keyArray()]; return clone; } - - valueOf() { - return this.cache; - } } module.exports = GuildMemberRoleManager; diff --git a/src/managers/MessageManager.js b/src/managers/MessageManager.js index 78395bbf4234..dbee780fea6b 100644 --- a/src/managers/MessageManager.js +++ b/src/managers/MessageManager.js @@ -1,19 +1,19 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const { TypeError } = require('../errors'); const Message = require('../structures/Message'); const MessagePayload = require('../structures/MessagePayload'); const Collection = require('../util/Collection'); -const LimitedCollection = require('../util/LimitedCollection'); /** * Manages API methods for Messages and holds their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class MessageManager extends BaseManager { +class MessageManager extends CachedManager { constructor(channel, iterable) { - super(channel.client, iterable, Message, LimitedCollection, channel.client.options.messageCacheMaxSize); + super(channel.client, Message, iterable); + /** * The channel that the messages belong to * @type {TextBasedChannel} diff --git a/src/managers/PermissionOverwriteManager.js b/src/managers/PermissionOverwriteManager.js index bd619828124d..9d43102fd3eb 100644 --- a/src/managers/PermissionOverwriteManager.js +++ b/src/managers/PermissionOverwriteManager.js @@ -1,6 +1,6 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const { TypeError } = require('../errors'); const PermissionOverwrites = require('../structures/PermissionOverwrites'); const Role = require('../structures/Role'); @@ -9,11 +9,11 @@ const { OverwriteTypes } = require('../util/Constants'); /** * Manages API methods for guild channel permission overwrites and stores their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class PermissionOverwriteManager extends BaseManager { +class PermissionOverwriteManager extends CachedManager { constructor(channel, iterable) { - super(channel.client, iterable, PermissionOverwrites); + super(channel.client, PermissionOverwrites, iterable); /** * The channel of the permission overwrite this manager belongs to diff --git a/src/managers/PresenceManager.js b/src/managers/PresenceManager.js index 1835e84b2700..f1f366e7b405 100644 --- a/src/managers/PresenceManager.js +++ b/src/managers/PresenceManager.js @@ -1,15 +1,15 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const { Presence } = require('../structures/Presence'); /** * Manages API methods for Presences and holds their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class PresenceManager extends BaseManager { +class PresenceManager extends CachedManager { constructor(client, iterable) { - super(client, iterable, Presence); + super(client, Presence, iterable); } /** diff --git a/src/managers/ReactionManager.js b/src/managers/ReactionManager.js index afafc6e84da6..ad58eb77d1ba 100644 --- a/src/managers/ReactionManager.js +++ b/src/managers/ReactionManager.js @@ -1,15 +1,15 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const MessageReaction = require('../structures/MessageReaction'); /** * Manages API methods for reactions and holds their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class ReactionManager extends BaseManager { +class ReactionManager extends CachedManager { constructor(message, iterable) { - super(message.client, iterable, MessageReaction); + super(message.client, MessageReaction, iterable); /** * The message that this manager belongs to diff --git a/src/managers/ReactionUserManager.js b/src/managers/ReactionUserManager.js index 4e4e294be2d0..d7e912189f71 100644 --- a/src/managers/ReactionUserManager.js +++ b/src/managers/ReactionUserManager.js @@ -1,16 +1,17 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const { Error } = require('../errors'); const Collection = require('../util/Collection'); /** * Manages API methods for users who reacted to a reaction and stores their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class ReactionUserManager extends BaseManager { - constructor(client, iterable, reaction) { - super(client, iterable, { name: 'User' }); +class ReactionUserManager extends CachedManager { + constructor(reaction, iterable) { + super(reaction.client, { name: 'User' }, iterable); + /** * The reaction that this manager belongs to * @type {MessageReaction} diff --git a/src/managers/RoleManager.js b/src/managers/RoleManager.js index 42074aa32807..8f2e4cd64dfc 100644 --- a/src/managers/RoleManager.js +++ b/src/managers/RoleManager.js @@ -1,6 +1,6 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const { TypeError } = require('../errors'); const Role = require('../structures/Role'); const Collection = require('../util/Collection'); @@ -9,11 +9,12 @@ const { resolveColor, setPosition } = require('../util/Util'); /** * Manages API methods for roles and stores their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class RoleManager extends BaseManager { +class RoleManager extends CachedManager { constructor(guild, iterable) { - super(guild.client, iterable, Role); + super(guild.client, Role, iterable); + /** * The guild belonging to this manager * @type {Guild} diff --git a/src/managers/StageInstanceManager.js b/src/managers/StageInstanceManager.js index 3ae0d8f17f0b..ec11eac12ec0 100644 --- a/src/managers/StageInstanceManager.js +++ b/src/managers/StageInstanceManager.js @@ -1,17 +1,17 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const { TypeError, Error } = require('../errors'); const StageInstance = require('../structures/StageInstance'); const { PrivacyLevels } = require('../util/Constants'); /** * Manages API methods for {@link StageInstance} objects and holds their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class StageInstanceManager extends BaseManager { +class StageInstanceManager extends CachedManager { constructor(guild, iterable) { - super(guild.client, iterable, StageInstance); + super(guild.client, StageInstance, iterable); /** * The guild this manager belongs to diff --git a/src/managers/ThreadManager.js b/src/managers/ThreadManager.js index 7587c9ba31cb..41f68349a3ef 100644 --- a/src/managers/ThreadManager.js +++ b/src/managers/ThreadManager.js @@ -1,6 +1,6 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const { TypeError } = require('../errors'); const ThreadChannel = require('../structures/ThreadChannel'); const Collection = require('../util/Collection'); @@ -8,11 +8,11 @@ const { ChannelTypes } = require('../util/Constants'); /** * Manages API methods for {@link ThreadChannel} objects and stores their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class ThreadManager extends BaseManager { +class ThreadManager extends CachedManager { constructor(channel, iterable) { - super(channel.client, iterable, ThreadChannel); + super(channel.client, ThreadChannel, iterable); /** * The channel this Manager belongs to diff --git a/src/managers/ThreadMemberManager.js b/src/managers/ThreadMemberManager.js index d66e88f66c62..2352dad67ead 100644 --- a/src/managers/ThreadMemberManager.js +++ b/src/managers/ThreadMemberManager.js @@ -1,17 +1,18 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const { TypeError } = require('../errors'); const ThreadMember = require('../structures/ThreadMember'); const Collection = require('../util/Collection'); /** - * Manages API methods for ThreadMembers and stores their cache. - * @extends {BaseManager} + * Manages API methods for GuildMembers and stores their cache. + * @extends {CachedManager} */ -class ThreadMemberManager extends BaseManager { +class ThreadMemberManager extends CachedManager { constructor(thread, iterable) { - super(thread.client, iterable, ThreadMember); + super(thread.client, ThreadMember, iterable); + /** * The thread this manager belongs to * @type {ThreadChannel} diff --git a/src/managers/UserManager.js b/src/managers/UserManager.js index e39105dd83d0..bcf481744383 100644 --- a/src/managers/UserManager.js +++ b/src/managers/UserManager.js @@ -1,6 +1,6 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); const GuildMember = require('../structures/GuildMember'); const Message = require('../structures/Message'); const ThreadMember = require('../structures/ThreadMember'); @@ -8,11 +8,11 @@ const User = require('../structures/User'); /** * Manages API methods for users and stores their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class UserManager extends BaseManager { +class UserManager extends CachedManager { constructor(client, iterable) { - super(client, iterable, User); + super(client, User, iterable); } /** diff --git a/src/managers/VoiceStateManager.js b/src/managers/VoiceStateManager.js index 35045f7b435d..2dc2db9203d3 100644 --- a/src/managers/VoiceStateManager.js +++ b/src/managers/VoiceStateManager.js @@ -1,14 +1,15 @@ 'use strict'; -const BaseManager = require('./BaseManager'); +const CachedManager = require('./CachedManager'); /** * Manages API methods for VoiceStates and stores their cache. - * @extends {BaseManager} + * @extends {CachedManager} */ -class VoiceStateManager extends BaseManager { +class VoiceStateManager extends CachedManager { constructor(guild, iterable) { - super(guild.client, iterable, { name: 'VoiceState' }); + super(guild.client, { name: 'VoiceState' }, iterable); + /** * The guild this manager belongs to * @type {Guild} diff --git a/src/structures/MessageReaction.js b/src/structures/MessageReaction.js index 4744cbef65a2..1648d6c8b7e1 100644 --- a/src/structures/MessageReaction.js +++ b/src/structures/MessageReaction.js @@ -22,6 +22,7 @@ class MessageReaction { * @readonly */ Object.defineProperty(this, 'client', { value: client }); + /** * The message that this reaction refers to * @type {Message} @@ -38,7 +39,7 @@ class MessageReaction { * A manager of the users that have given this reaction * @type {ReactionUserManager} */ - this.users = new ReactionUserManager(client, undefined, this); + this.users = new ReactionUserManager(this); this._emoji = new ReactionEmoji(this, data.emoji); diff --git a/src/util/Constants.js b/src/util/Constants.js index 3c4325879ad9..bb779f50037d 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -3,117 +3,6 @@ const Package = (exports.Package = require('../../package.json')); const { Error, RangeError } = require('../errors'); -/** - * Rate limit data - * @typedef {Object} RateLimitData - * @property {number} timeout Time until this rate limit ends, in ms - * @property {number} limit The maximum amount of requests of this endpoint - * @property {string} method The http method of this request - * @property {string} path The path of the request relative to the HTTP endpoint - * @property {string} route The route of the request relative to the HTTP endpoint - * @property {boolean} global Whether this is a global rate limit - */ - -/** - * Whether this rate limit should throw an Error - * @typedef {Function} RateLimitQueueFilter - * @param {RateLimitData} rateLimitData The data of this rate limit - * @returns {boolean|Promise} - */ - -/** - * Options for a client. - * @typedef {Object} ClientOptions - * @property {number|number[]|string} [shards] ID of the shard to run, or an array of shard IDs. If not specified, - * the client will spawn {@link ClientOptions#shardCount} shards. If set to `auto`, it will fetch the - * recommended amount of shards from Discord and spawn that amount - * @property {number} [shardCount=1] The total amount of shards used by all processes of this bot - * (e.g. recommended shard count, shard count of the ShardingManager) - * @property {number} [messageCacheMaxSize=200] Maximum number of messages to cache per channel - * (-1 or Infinity for unlimited - don't do this without message sweeping, otherwise memory usage will climb - * indefinitely) - * @property {number} [messageCacheLifetime=0] How long a message should stay in the cache until it is considered - * sweepable (in seconds, 0 for forever) - * @property {number} [messageSweepInterval=0] How frequently to remove messages from the cache that are older than - * the message cache lifetime (in seconds, 0 for never) - * @property {MessageMentionOptions} [allowedMentions] Default value for {@link MessageOptions#allowedMentions} - * @property {number} [invalidRequestWarningInterval=0] The number of invalid REST requests (those that return - * 401, 403, or 429) in a 10 minute window between emitted warnings (0 for no warnings). That is, if set to 500, - * warnings will be emitted at invalid request number 500, 1000, 1500, and so on. - * @property {PartialType[]} [partials] Structures allowed to be partial. This means events can be emitted even when - * they're missing all the data for a particular structure. See the "Partial Structures" topic on the - * [guide](https://discordjs.guide/popular-topics/partials.html) for some - * important usage information, as partials require you to put checks in place when handling data. - * @property {number} [restWsBridgeTimeout=5000] Maximum time permitted between REST responses and their - * corresponding websocket events - * @property {number} [restTimeOffset=500] Extra time in milliseconds to wait before continuing to make REST - * requests (higher values will reduce rate-limiting errors on bad connections) - * @property {number} [restRequestTimeout=15000] Time to wait before cancelling a REST request, in milliseconds - * @property {number} [restSweepInterval=60] How frequently to delete inactive request buckets, in seconds - * (or 0 for never) - * @property {number} [restGlobalRateLimit=0] How many requests to allow sending per second (0 for unlimited, 50 for - * the standard global limit used by Discord) - * @property {string[]|RateLimitQueueFilter} [rejectOnRateLimit] Decides how rate limits and pre-emptive throttles - * should be handled. If this option is an array containing the prefix of the request route (e.g. /channels to match any - * route starting with /channels, such as /channels/222197033908436994/messages) or a function returning true, a - * {@link RateLimitError} will be thrown. Otherwise the request will be queued for later - * @property {number} [retryLimit=1] How many times to retry on 5XX errors (Infinity for indefinite amount of retries) - * @property {PresenceData} [presence={}] Presence data to use upon login - * @property {IntentsResolvable} intents Intents to enable for this connection - * @property {WebsocketOptions} [ws] Options for the WebSocket - * @property {HTTPOptions} [http] HTTP options - */ -exports.DefaultOptions = { - shardCount: 1, - messageCacheMaxSize: 200, - messageCacheLifetime: 0, - messageSweepInterval: 0, - invalidRequestWarningInterval: 0, - partials: [], - restWsBridgeTimeout: 5000, - restRequestTimeout: 15000, - restGlobalRateLimit: 0, - retryLimit: 1, - restTimeOffset: 500, - restSweepInterval: 60, - presence: {}, - - /** - * WebSocket options (these are left as snake_case to match the API) - * @typedef {Object} WebsocketOptions - * @property {number} [large_threshold=50] Number of members in a guild after which offline users will no longer be - * sent in the initial guild member list, must be between 50 and 250 - */ - ws: { - large_threshold: 50, - compress: false, - properties: { - $os: process.platform, - $browser: 'discord.js', - $device: 'discord.js', - }, - version: 9, - }, - - /** - * HTTP options - * @typedef {Object} HTTPOptions - * @property {number} [version=9] API version to use - * @property {string} [api='https://discord.com/api'] Base url of the API - * @property {string} [cdn='https://cdn.discordapp.com'] Base url of the CDN - * @property {string} [invite='https://discord.gg'] Base url of invites - * @property {string} [template='https://discord.new'] Base url of templates - * @property {Object} [headers] Additional headers to send for all API requests - */ - http: { - version: 9, - api: 'https://discord.com/api', - cdn: 'https://cdn.discordapp.com', - invite: 'https://discord.gg', - template: 'https://discord.new', - }, -}; - exports.UserAgent = `DiscordBot (${Package.homepage.split('#')[0]}, ${Package.version}) Node.js/${process.version}`; exports.WSCodes = { diff --git a/src/util/Options.js b/src/util/Options.js new file mode 100644 index 000000000000..ef5d6bf32d2e --- /dev/null +++ b/src/util/Options.js @@ -0,0 +1,154 @@ +'use strict'; + +/** + * Rate limit data + * @typedef {Object} RateLimitData + * @property {number} timeout Time until this rate limit ends, in ms + * @property {number} limit The maximum amount of requests of this endpoint + * @property {string} method The http method of this request + * @property {string} path The path of the request relative to the HTTP endpoint + * @property {string} route The route of the request relative to the HTTP endpoint + * @property {boolean} global Whether this is a global rate limit + */ + +/** + * Whether this rate limit should throw an Error + * @typedef {Function} RateLimitQueueFilter + * @param {RateLimitData} rateLimitData The data of this rate limit + * @returns {boolean|Promise} + */ + +/** + * @typedef {Function} CacheFactory + * @param {Function} holds The class that the cache will hold. + * @returns {Collection} Cache instance that follows collection interface. + */ + +/** + * Options for a client. + * @typedef {Object} ClientOptions + * @property {number|number[]|string} [shards] ID of the shard to run, or an array of shard IDs. If not specified, + * the client will spawn {@link ClientOptions#shardCount} shards. If set to `auto`, it will fetch the + * recommended amount of shards from Discord and spawn that amount + * @property {number} [shardCount=1] The total amount of shards used by all processes of this bot + * (e.g. recommended shard count, shard count of the ShardingManager) + * @property {CacheFactory} [makeCache] Function to create a cache. + * (-1 or Infinity for unlimited - don't do this without message sweeping, otherwise memory usage will climb + * indefinitely) + * @property {number} [messageCacheLifetime=0] How long a message should stay in the cache until it is considered + * sweepable (in seconds, 0 for forever) + * @property {number} [messageSweepInterval=0] How frequently to remove messages from the cache that are older than + * the message cache lifetime (in seconds, 0 for never) + * @property {MessageMentionOptions} [allowedMentions] Default value for {@link MessageOptions#allowedMentions} + * @property {number} [invalidRequestWarningInterval=0] The number of invalid REST requests (those that return + * 401, 403, or 429) in a 10 minute window between emitted warnings (0 for no warnings). That is, if set to 500, + * warnings will be emitted at invalid request number 500, 1000, 1500, and so on. + * @property {PartialType[]} [partials] Structures allowed to be partial. This means events can be emitted even when + * they're missing all the data for a particular structure. See the "Partial Structures" topic on the + * [guide](https://discordjs.guide/popular-topics/partials.html) for some + * important usage information, as partials require you to put checks in place when handling data. + * @property {number} [restWsBridgeTimeout=5000] Maximum time permitted between REST responses and their + * corresponding websocket events + * @property {number} [restTimeOffset=500] Extra time in milliseconds to wait before continuing to make REST + * requests (higher values will reduce rate-limiting errors on bad connections) + * @property {number} [restRequestTimeout=15000] Time to wait before cancelling a REST request, in milliseconds + * @property {number} [restSweepInterval=60] How frequently to delete inactive request buckets, in seconds + * (or 0 for never) + * @property {number} [restGlobalRateLimit=0] How many requests to allow sending per second (0 for unlimited, 50 for + * the standard global limit used by Discord) + * @property {string[]|RateLimitQueueFilter} [rejectOnRateLimit] Decides how rate limits and pre-emptive throttles + * should be handled. If this option is an array containing the prefix of the request route (e.g. /channels to match any + * route starting with /channels, such as /channels/222197033908436994/messages) or a function returning true, a + * {@link RateLimitError} will be thrown. Otherwise the request will be queued for later + * @property {number} [retryLimit=1] How many times to retry on 5XX errors (Infinity for indefinite amount of retries) + * @property {PresenceData} [presence={}] Presence data to use upon login + * @property {IntentsResolvable} intents Intents to enable for this connection + * @property {WebsocketOptions} [ws] Options for the WebSocket + * @property {HTTPOptions} [http] HTTP options + */ + +/** + * WebSocket options (these are left as snake_case to match the API) + * @typedef {Object} WebsocketOptions + * @property {number} [large_threshold=50] Number of members in a guild after which offline users will no longer be + * sent in the initial guild member list, must be between 50 and 250 + */ + +/** + * HTTP options + * @typedef {Object} HTTPOptions + * @property {number} [version=9] API version to use + * @property {string} [api='https://discord.com/api'] Base url of the API + * @property {string} [cdn='https://cdn.discordapp.com'] Base url of the CDN + * @property {string} [invite='https://discord.gg'] Base url of invites + * @property {string} [template='https://discord.new'] Base url of templates + * @property {Object} [headers] Additional headers to send for all API requests + */ + +/** + * Contains various utilities for client options. + */ +class ClientOptionsUtil extends null { + constructor() { + throw new Error(`The ${this.constructor.name} class may not be instantiated.`); + } + + /** + * The default client options. + * @returns {ClientOptions} + */ + static createDefaultOptions() { + return { + shardCount: 1, + makeCache: this.cacheWithLimits({ Message: 200 }), + messageCacheLifetime: 0, + messageSweepInterval: 0, + invalidRequestWarningInterval: 0, + partials: [], + restWsBridgeTimeout: 5000, + restRequestTimeout: 15000, + restGlobalRateLimit: 0, + retryLimit: 1, + restTimeOffset: 500, + restSweepInterval: 60, + presence: {}, + ws: { + large_threshold: 50, + compress: false, + properties: { + $os: process.platform, + $browser: 'discord.js', + $device: 'discord.js', + }, + version: 9, + }, + http: { + version: 9, + api: 'https://discord.com/api', + cdn: 'https://cdn.discordapp.com', + invite: 'https://discord.gg', + template: 'https://discord.new', + }, + }; + } + + /** + * Create a cache factory using predefined limits. + * @param {Partial>} [limits={}] Limits for structures. + * @returns {CacheFactory} + */ + static cacheWithLimits(limits = {}) { + const Collection = require('./Collection'); + const LimitedCollection = require('./LimitedCollection'); + + return holds => { + const limit = limits[holds.name]; + if (limit === null || limit === undefined || limit === Infinity) { + return new Collection(); + } + return new LimitedCollection(limit); + }; + } +} + +module.exports = ClientOptionsUtil; diff --git a/src/util/Util.js b/src/util/Util.js index e891182daa92..2a4984546d6b 100644 --- a/src/util/Util.js +++ b/src/util/Util.js @@ -2,7 +2,8 @@ const { parse } = require('path'); const fetch = require('node-fetch'); -const { Colors, DefaultOptions, Endpoints } = require('./Constants'); +const { Colors, Endpoints } = require('./Constants'); +const Options = require('./Options'); const { Error: DiscordError, RangeError, TypeError } = require('../errors'); const has = (o, k) => Object.prototype.hasOwnProperty.call(o, k); const isObject = d => typeof d === 'object' && d !== null; @@ -261,7 +262,8 @@ class Util extends null { */ static fetchRecommendedShards(token, guildsPerShard = 1000) { if (!token) throw new DiscordError('TOKEN_MISSING'); - return fetch(`${DefaultOptions.http.api}/v${DefaultOptions.http.version}${Endpoints.botGateway}`, { + const defaults = Options.createDefaultOptions(); + return fetch(`${defaults.http.api}/v${defaults.http.version}${Endpoints.botGateway}`, { method: 'GET', headers: { Authorization: `Bot ${token.replace(/^Bot\s*/i, '')}` }, }) diff --git a/test/tester2000.js b/test/tester2000.js new file mode 100644 index 000000000000..ed3307c94261 --- /dev/null +++ b/test/tester2000.js @@ -0,0 +1,57 @@ +'use strict'; + +const { token, prefix, owner } = require('./auth.js'); +const { Client, Options, Intents } = require('../src'); + +// eslint-disable-next-line no-console +const log = (...args) => console.log(process.uptime().toFixed(3), ...args); + +const client = new Client({ + intents: Intents.ALL, + makeCache: Options.cacheWithLimits({ + Message: 10, + Presence: 10, + }), +}); + +client.on('debug', log); +client.on('ready', () => { + log('READY', client.user.tag, client.user.id); +}); +client.on('rateLimit', log); +client.on('error', console.error); + +const commands = { + eval: message => { + if (message.author.id !== owner) return; + let res; + try { + res = eval(message.content); + if (typeof res !== 'string') res = require('util').inspect(res); + } catch (err) { + // eslint-disable-next-line no-console + console.error(err.stack); + res = err.message; + } + message.channel.send(res, { code: 'js' }); + }, + ping: message => message.channel.send('pong'), +}; + +client.on('message', message => { + if (!message.content.startsWith(prefix) || message.author.bot) return; + + message.content = message.content.replace(prefix, '').trim().split(' '); + const command = message.content.shift(); + message.content = message.content.join(' '); + + // eslint-disable-next-line no-console + console.log('COMMAND', command, message.content); + + if (command in commands) commands[command](message); +}); + +client.login(token); + +// eslint-disable-next-line no-console +process.on('unhandledRejection', console.error); diff --git a/typings/index.d.ts b/typings/index.d.ts index 423be4069515..7a155b870680 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -526,6 +526,11 @@ declare module 'discord.js' { public setUsername(username: string): Promise; } + export class ClientOptionsUtil { + public static createDefaultOptions(): ClientOptions; + public static cacheWithLimits(limits?: Partial>): CacheFactory; + } + export class ClientVoiceManager { constructor(client: Client); public readonly client: Client; @@ -608,7 +613,6 @@ declare module 'discord.js' { devDependencies: { [key: string]: string }; [key: string]: any; }; - DefaultOptions: ClientOptions; UserAgent: string | null; Endpoints: { botGateway: string; @@ -2340,13 +2344,15 @@ declare module 'discord.js' { //#region Managers - export abstract class BaseManager { - constructor(client: Client, iterable: Iterable, holds: Constructable, cacheType: Collection); - public holds: Constructable; - public cache: Collection; - public cacheType: Collection; + export abstract class BaseManager { + constructor(client: Client); public readonly client: Client; - public add(data: any, cache?: boolean, { id, extras }?: { id: K; extras: any[] }): Holds; + } + + export abstract class DataManager extends BaseManager { + constructor(client: Client, holds: Constructable); + public readonly holds: Constructable; + public readonly cache: Collection; public resolve(resolvable: Holds): Holds; public resolve(resolvable: R): Holds | null; public resolveID(resolvable: Holds): K; @@ -2354,11 +2360,16 @@ declare module 'discord.js' { public valueOf(): Collection; } + export abstract class CachedManager extends DataManager { + constructor(client: Client, holds: Constructable); + public add(data: any, cache?: boolean, { id, extras }?: { id: K; extras: any[] }): Holds; + } + export class ApplicationCommandManager< ApplicationCommandType = ApplicationCommand<{ guild: GuildResolvable }>, PermissionsOptionsExtras = { guild: GuildResolvable }, PermissionsGuildType = null, - > extends BaseManager { + > extends CachedManager { constructor(client: Client, iterable?: Iterable); public permissions: ApplicationCommandPermissionsManager< { command?: ApplicationCommandResolvable } & PermissionsOptionsExtras, @@ -2400,7 +2411,12 @@ declare module 'discord.js' { private static transformCommand(command: ApplicationCommandData): unknown; } - export class ApplicationCommandPermissionsManager { + export class ApplicationCommandPermissionsManager< + BaseOptions, + FetchSingleOptions, + GuildType, + CommandIDType, + > extends BaseManager { constructor(manager: ApplicationCommandManager | GuildApplicationCommandManager | ApplicationCommand); public client: Client; public commandID: CommandIDType; @@ -2436,12 +2452,12 @@ declare module 'discord.js' { private static transformPermissions(permissions: ApplicationCommandPermissionData, received?: boolean): unknown; } - export class BaseGuildEmojiManager extends BaseManager { + export class BaseGuildEmojiManager extends CachedManager { constructor(client: Client, iterable?: Iterable); public resolveIdentifier(emoji: EmojiIdentifierResolvable): string | null; } - export class ChannelManager extends BaseManager { + export class ChannelManager extends CachedManager { constructor(client: Client, iterable: Iterable); public fetch(id: Snowflake, options?: BaseFetchOptions): Promise; } @@ -2457,7 +2473,7 @@ declare module 'discord.js' { public set(commands: ApplicationCommandData[]): Promise>; } - export class GuildChannelManager extends BaseManager< + export class GuildChannelManager extends CachedManager< Snowflake, GuildChannel | ThreadChannel, GuildChannelResolvable @@ -2499,11 +2515,10 @@ declare module 'discord.js' { public fetch(id?: Snowflake, options?: BaseFetchOptions): Promise>; } - export class GuildEmojiRoleManager { + export class GuildEmojiRoleManager extends DataManager { constructor(emoji: GuildEmoji); public emoji: GuildEmoji; public guild: Guild; - public cache: Collection; public add( roleOrRoles: RoleResolvable | readonly RoleResolvable[] | Collection, ): Promise; @@ -2511,17 +2526,16 @@ declare module 'discord.js' { public remove( roleOrRoles: RoleResolvable | readonly RoleResolvable[] | Collection, ): Promise; - public valueOf(): Collection; } - export class GuildManager extends BaseManager { + export class GuildManager extends CachedManager { constructor(client: Client, iterable?: Iterable); public create(name: string, options?: GuildCreateOptions): Promise; public fetch(options: Snowflake | FetchGuildOptions): Promise; public fetch(options?: FetchGuildsOptions): Promise>; } - export class GuildMemberManager extends BaseManager { + export class GuildMemberManager extends CachedManager { constructor(guild: Guild, iterable?: Iterable); public guild: Guild; public ban(user: UserResolvable, options?: BanOptions): Promise; @@ -2537,7 +2551,7 @@ declare module 'discord.js' { public unban(user: UserResolvable, reason?: string): Promise; } - export class GuildBanManager extends BaseManager { + export class GuildBanManager extends CachedManager { constructor(guild: Guild, iterable?: Iterable); public guild: Guild; public create(user: UserResolvable, options?: BanOptions): Promise; @@ -2546,9 +2560,8 @@ declare module 'discord.js' { public remove(user: UserResolvable, reason?: string): Promise; } - export class GuildMemberRoleManager { + export class GuildMemberRoleManager extends DataManager { constructor(member: GuildMember); - public readonly cache: Collection; public readonly hoist: Role | null; public readonly color: Role | null; public readonly highest: Role; @@ -2566,10 +2579,9 @@ declare module 'discord.js' { roleOrRoles: RoleResolvable | readonly RoleResolvable[] | Collection, reason?: string, ): Promise; - public valueOf(): Collection; } - export class MessageManager extends BaseManager { + export class MessageManager extends CachedManager { constructor(channel: TextChannel | DMChannel | ThreadChannel, iterable?: Iterable); public channel: TextBasedChannelFields; public cache: Collection; @@ -2587,7 +2599,7 @@ declare module 'discord.js' { public unpin(message: MessageResolvable): Promise; } - export class PermissionOverwriteManager extends BaseManager< + export class PermissionOverwriteManager extends CachedManager< Snowflake, PermissionOverwrites, PermissionOverwriteResolvable @@ -2616,24 +2628,24 @@ declare module 'discord.js' { public delete(userOrRole: RoleResolvable | UserResolvable, reason?: string): Promise; } - export class PresenceManager extends BaseManager { + export class PresenceManager extends CachedManager { constructor(client: Client, iterable?: Iterable); } - export class ReactionManager extends BaseManager { + export class ReactionManager extends CachedManager { constructor(message: Message, iterable?: Iterable); public message: Message; public removeAll(): Promise; } - export class ReactionUserManager extends BaseManager { - constructor(client: Client, iterable: Iterable | undefined, reaction: MessageReaction); + export class ReactionUserManager extends CachedManager { + constructor(reaction: MessageReaction, iterable?: Iterable); public reaction: MessageReaction; public fetch(options?: FetchReactionUsersOptions): Promise>; public remove(user?: UserResolvable): Promise; } - export class RoleManager extends BaseManager { + export class RoleManager extends CachedManager { constructor(guild: Guild, iterable?: Iterable); public readonly everyone: Role; public readonly highest: Role; @@ -2646,7 +2658,7 @@ declare module 'discord.js' { public edit(role: RoleResolvable, options: RoleData, reason?: string): Promise; } - export class StageInstanceManager extends BaseManager { + export class StageInstanceManager extends CachedManager { constructor(guild: Guild, iterable?: Iterable); public guild: Guild; public create(channel: StageChannel | Snowflake, options: StageInstanceCreateOptions): Promise; @@ -2655,7 +2667,7 @@ declare module 'discord.js' { public delete(channel: StageChannel | Snowflake): Promise; } - export class ThreadManager extends BaseManager { + export class ThreadManager extends CachedManager { constructor(channel: TextChannel | NewsChannel, iterable?: Iterable); public channel: TextChannel | NewsChannel; public create(options: ThreadCreateOptions): Promise; @@ -2666,7 +2678,7 @@ declare module 'discord.js' { } export interface ThreadMemberManager - extends Omit, 'add'> {} + extends Omit, 'add'> {} export class ThreadMemberManager { constructor(thread: ThreadChannel, iterable?: Iterable); public thread: ThreadChannel; @@ -2676,12 +2688,12 @@ declare module 'discord.js' { public remove(id: Snowflake | '@me', reason?: string): Promise; } - export class UserManager extends BaseManager { + export class UserManager extends CachedManager { constructor(client: Client, iterable?: Iterable); public fetch(id: Snowflake, options?: BaseFetchOptions): Promise; } - export class VoiceStateManager extends BaseManager { + export class VoiceStateManager extends CachedManager { constructor(guild: Guild, iterable?: Iterable); public guild: Guild; } @@ -3008,6 +3020,8 @@ declare module 'discord.js' { type BufferResolvable = Buffer | string; + type CacheFactory = (holds: { name: string }) => Collection; + interface ChannelCreationOverwrites { allow?: PermissionResolvable; deny?: PermissionResolvable; @@ -3133,7 +3147,7 @@ declare module 'discord.js' { interface ClientOptions { shards?: number | number[] | 'auto'; shardCount?: number; - messageCacheMaxSize?: number; + makeCache?: CacheFactory; messageCacheLifetime?: number; messageSweepInterval?: number; allowedMentions?: MessageMentionOptions; diff --git a/typings/index.ts b/typings/index.ts index a11c13659974..8b69ae258477 100644 --- a/typings/index.ts +++ b/typings/index.ts @@ -2,6 +2,7 @@ import { Client, + ClientOptionsUtil, Collection, Intents, Message, @@ -17,6 +18,9 @@ import { const client: Client = new Client({ intents: Intents.NON_PRIVILEGED, + makeCache: ClientOptionsUtil.cacheWithLimits({ + Message: 200, + }), }); const testGuildID = '222078108977594368'; // DJS From 582c5c715f5489923c42f18474ec90dcdd36198a Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Sat, 3 Jul 2021 00:11:05 -0400 Subject: [PATCH 02/14] feat(Managers): use manager name instead of holds' --- src/managers/CachedManager.js | 2 +- src/util/Options.js | 5 +++-- test/tester2000.js | 4 ++-- typings/index.d.ts | 2 +- typings/index.ts | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/managers/CachedManager.js b/src/managers/CachedManager.js index 8552bac467fa..051b38e38e0b 100644 --- a/src/managers/CachedManager.js +++ b/src/managers/CachedManager.js @@ -11,7 +11,7 @@ class CachedManager extends DataManager { constructor(client, holds, iterable) { super(client, holds); - Object.defineProperty(this, '_cache', { value: this.client.options.makeCache(this.holds) }); + Object.defineProperty(this, '_cache', { value: this.client.options.makeCache(this.constructor, this.holds) }); if (iterable) { for (const item of iterable) { diff --git a/src/util/Options.js b/src/util/Options.js index ef5d6bf32d2e..ca36fea809fd 100644 --- a/src/util/Options.js +++ b/src/util/Options.js @@ -20,6 +20,7 @@ /** * @typedef {Function} CacheFactory + * @param {Function} manager The manager class the cache is being requested from. * @param {Function} holds The class that the cache will hold. * @returns {Collection} Cache instance that follows collection interface. */ @@ -141,8 +142,8 @@ class ClientOptionsUtil extends null { const Collection = require('./Collection'); const LimitedCollection = require('./LimitedCollection'); - return holds => { - const limit = limits[holds.name]; + return manager => { + const limit = limits[manager.name]; if (limit === null || limit === undefined || limit === Infinity) { return new Collection(); } diff --git a/test/tester2000.js b/test/tester2000.js index ed3307c94261..e42d6b8a6f3d 100644 --- a/test/tester2000.js +++ b/test/tester2000.js @@ -9,8 +9,8 @@ const log = (...args) => console.log(process.uptime().toFixed(3), ...args); const client = new Client({ intents: Intents.ALL, makeCache: Options.cacheWithLimits({ - Message: 10, - Presence: 10, + MessageManager: 10, + PresenceManager: 10, }), }); diff --git a/typings/index.d.ts b/typings/index.d.ts index 7a155b870680..ca04c45b5ebc 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -3020,7 +3020,7 @@ declare module 'discord.js' { type BufferResolvable = Buffer | string; - type CacheFactory = (holds: { name: string }) => Collection; + type CacheFactory = (manager: { name: string }, holds: { name: string }) => Collection; interface ChannelCreationOverwrites { allow?: PermissionResolvable; diff --git a/typings/index.ts b/typings/index.ts index 8b69ae258477..c154c8d5e4a5 100644 --- a/typings/index.ts +++ b/typings/index.ts @@ -19,7 +19,7 @@ import { const client: Client = new Client({ intents: Intents.NON_PRIVILEGED, makeCache: ClientOptionsUtil.cacheWithLimits({ - Message: 200, + MessageManager: 200, }), }); From d2ef1b29be2721debcb94ef5b024ebe5782873c2 Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Sat, 3 Jul 2021 00:11:56 -0400 Subject: [PATCH 03/14] fix(Options): fix Options typings --- typings/index.d.ts | 2 +- typings/index.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/typings/index.d.ts b/typings/index.d.ts index ca04c45b5ebc..4d886beabacd 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -526,7 +526,7 @@ declare module 'discord.js' { public setUsername(username: string): Promise; } - export class ClientOptionsUtil { + export class Options { public static createDefaultOptions(): ClientOptions; public static cacheWithLimits(limits?: Partial>): CacheFactory; } diff --git a/typings/index.ts b/typings/index.ts index c154c8d5e4a5..b7939ca4f4e4 100644 --- a/typings/index.ts +++ b/typings/index.ts @@ -2,7 +2,7 @@ import { Client, - ClientOptionsUtil, + Options, Collection, Intents, Message, @@ -18,7 +18,7 @@ import { const client: Client = new Client({ intents: Intents.NON_PRIVILEGED, - makeCache: ClientOptionsUtil.cacheWithLimits({ + makeCache: Options.cacheWithLimits({ MessageManager: 200, }), }); From 37073f25e384dede84f79715a1f75791970dd1bf Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Sat, 3 Jul 2021 00:15:32 -0400 Subject: [PATCH 04/14] fix(Options): fix default cache --- src/util/Options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/Options.js b/src/util/Options.js index ca36fea809fd..3a11508a17a8 100644 --- a/src/util/Options.js +++ b/src/util/Options.js @@ -101,7 +101,7 @@ class ClientOptionsUtil extends null { static createDefaultOptions() { return { shardCount: 1, - makeCache: this.cacheWithLimits({ Message: 200 }), + makeCache: this.cacheWithLimits({ MessageManager: 200 }), messageCacheLifetime: 0, messageSweepInterval: 0, invalidRequestWarningInterval: 0, From 07d10c99b2f94fcac2fb5d3e1b05b6a67146b00e Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Sat, 3 Jul 2021 00:15:50 -0400 Subject: [PATCH 05/14] feat(Options): add some more cache helpers --- src/util/Options.js | 18 ++++++++++++++++++ typings/index.d.ts | 2 ++ 2 files changed, 20 insertions(+) diff --git a/src/util/Options.js b/src/util/Options.js index 3a11508a17a8..13da4223295b 100644 --- a/src/util/Options.js +++ b/src/util/Options.js @@ -150,6 +150,24 @@ class ClientOptionsUtil extends null { return new LimitedCollection(limit); }; } + + /** + * Create a cache factory that always caches everything. + * @returns {CacheFactory} + */ + static cacheEverything() { + const Collection = require('./Collection'); + return () => new Collection(); + } + + /** + * Create a cache factory that always caches nothing. + * @returns {CacheFactory} + */ + static cacheNothing() { + const LimitedCollection = require('./LimitedCollection'); + return () => new LimitedCollection(0); + } } module.exports = ClientOptionsUtil; diff --git a/typings/index.d.ts b/typings/index.d.ts index 4d886beabacd..4698db0ad289 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -529,6 +529,8 @@ declare module 'discord.js' { export class Options { public static createDefaultOptions(): ClientOptions; public static cacheWithLimits(limits?: Partial>): CacheFactory; + public static cacheEverything(): CacheFactory; + public static cacheNothing(): CacheFactory; } export class ClientVoiceManager { From 28d1dc4e32f27262193736b70c300ce5604325bb Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Sat, 3 Jul 2021 00:21:51 -0400 Subject: [PATCH 06/14] fix(Options): forgot to rename --- src/util/Options.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/Options.js b/src/util/Options.js index 13da4223295b..988c34527b5e 100644 --- a/src/util/Options.js +++ b/src/util/Options.js @@ -89,7 +89,7 @@ /** * Contains various utilities for client options. */ -class ClientOptionsUtil extends null { +class Options extends null { constructor() { throw new Error(`The ${this.constructor.name} class may not be instantiated.`); } @@ -170,4 +170,4 @@ class ClientOptionsUtil extends null { } } -module.exports = ClientOptionsUtil; +module.exports = Options; From 08a5d5d8f8a2a9b7ed2491f47562825823bd0229 Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Sat, 3 Jul 2021 01:00:53 -0400 Subject: [PATCH 07/14] fix(Test): codeblock formatting --- test/tester2000.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/tester2000.js b/test/tester2000.js index e42d6b8a6f3d..3d52b81fbe04 100644 --- a/test/tester2000.js +++ b/test/tester2000.js @@ -1,7 +1,7 @@ 'use strict'; const { token, prefix, owner } = require('./auth.js'); -const { Client, Options, Intents } = require('../src'); +const { Client, Options, Intents, Formatters } = require('../src'); // eslint-disable-next-line no-console const log = (...args) => console.log(process.uptime().toFixed(3), ...args); @@ -33,7 +33,7 @@ const commands = { console.error(err.stack); res = err.message; } - message.channel.send(res, { code: 'js' }); + message.channel.send(Formatters.codeBlock(res)); }, ping: message => message.channel.send('pong'), }; From 73f241e9405c1f6c40ded02003d0f6fa5281f65b Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Sat, 3 Jul 2021 01:09:58 -0400 Subject: [PATCH 08/14] docs(Managers): more specific docs for new managers --- src/managers/CachedManager.js | 2 +- src/managers/DataManager.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/managers/CachedManager.js b/src/managers/CachedManager.js index 051b38e38e0b..78ecfc6e120c 100644 --- a/src/managers/CachedManager.js +++ b/src/managers/CachedManager.js @@ -3,7 +3,7 @@ const DataManager = require('./DataManager'); /** - * Manager that holds a cache. + * Manages the API methods of a data model with a mutable cache of instances. * @extends {DataManager} * @abstract */ diff --git a/src/managers/DataManager.js b/src/managers/DataManager.js index bbb09c21e7c3..3b6c362e6efa 100644 --- a/src/managers/DataManager.js +++ b/src/managers/DataManager.js @@ -5,7 +5,7 @@ const BaseManager = require('./BaseManager'); let Structures; /** - * Manager that holds data structures. + * Manages the API methods of a data model along with a collection of instances. * @extends {BaseManager} * @abstract */ @@ -17,7 +17,7 @@ class DataManager extends BaseManager { /** * The data structure belonging to this manager. - * @name BaseManager#holds + * @name DataManager#holds * @type {Function} * @private * @readonly From 27744614e61a3f6b2cc1db95a5da8cee406f145c Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Sat, 3 Jul 2021 01:10:19 -0400 Subject: [PATCH 09/14] refactor(Options): remove uneeded constructor --- src/util/Options.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/util/Options.js b/src/util/Options.js index 988c34527b5e..11d06a8f62c1 100644 --- a/src/util/Options.js +++ b/src/util/Options.js @@ -90,10 +90,6 @@ * Contains various utilities for client options. */ class Options extends null { - constructor() { - throw new Error(`The ${this.constructor.name} class may not be instantiated.`); - } - /** * The default client options. * @returns {ClientOptions} From 0fdae4805f9a82a1427081469a205bf021f21d60 Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Sat, 3 Jul 2021 01:15:47 -0400 Subject: [PATCH 10/14] refactor(Manager): add error message string --- src/errors/Messages.js | 2 ++ src/managers/DataManager.js | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/errors/Messages.js b/src/errors/Messages.js index 00290a1b632c..30a5e9b9ae16 100644 --- a/src/errors/Messages.js +++ b/src/errors/Messages.js @@ -127,6 +127,8 @@ const Messages = { INTERACTION_NOT_REPLIED: 'This interaction has not been deferred or replied to.', INTERACTION_EPHEMERAL_REPLIED: 'Ephemeral responses cannot be fetched or deleted.', INTERACTION_FETCH_EPHEMERAL: 'Ephemeral responses cannot be fetched.', + + NOT_IMPLEMENTED: (what, name) => `Method ${what} not implemented on ${name}.`, }; for (const [name, message] of Object.entries(Messages)) register(name, message); diff --git a/src/managers/DataManager.js b/src/managers/DataManager.js index 3b6c362e6efa..cd304d956347 100644 --- a/src/managers/DataManager.js +++ b/src/managers/DataManager.js @@ -1,6 +1,7 @@ 'use strict'; const BaseManager = require('./BaseManager'); +const { Error } = require('../errors'); let Structures; @@ -31,7 +32,7 @@ class DataManager extends BaseManager { * @abstract */ get cache() { - throw new Error(`Getter 'cache' not implemented for ${this.constructor.name}`); + throw new Error('NOT_IMPLEMENTED', 'get cache', this.constructor.name); } /** From be7a258d839b2939f41a12430c6654ea490ac6d2 Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Sat, 3 Jul 2021 01:57:26 -0400 Subject: [PATCH 11/14] refactor(Options): rename createDefaultOptions --- src/client/BaseClient.js | 2 +- src/client/Client.js | 2 +- src/util/Options.js | 2 +- src/util/Util.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client/BaseClient.js b/src/client/BaseClient.js index ad9f26c35525..f501b3a9db7a 100644 --- a/src/client/BaseClient.js +++ b/src/client/BaseClient.js @@ -38,7 +38,7 @@ class BaseClient extends EventEmitter { * The options the client was instantiated with * @type {ClientOptions} */ - this.options = Util.mergeDefault(Options.createDefaultOptions(), options); + this.options = Util.mergeDefault(Options.createDefault(), options); /** * The REST manager of the client diff --git a/src/client/Client.js b/src/client/Client.js index 97b165def123..763379d85b63 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -36,7 +36,7 @@ class Client extends BaseClient { super(Object.assign({ _tokenType: 'Bot' }, options)); const data = require('worker_threads').workerData ?? process.env; - const defaults = Options.createDefaultOptions(); + const defaults = Options.createDefault(); if (this.options.shards === defaults.shards) { if ('SHARDS' in data) { diff --git a/src/util/Options.js b/src/util/Options.js index 11d06a8f62c1..08cde855fc1a 100644 --- a/src/util/Options.js +++ b/src/util/Options.js @@ -94,7 +94,7 @@ class Options extends null { * The default client options. * @returns {ClientOptions} */ - static createDefaultOptions() { + static createDefault() { return { shardCount: 1, makeCache: this.cacheWithLimits({ MessageManager: 200 }), diff --git a/src/util/Util.js b/src/util/Util.js index 2a4984546d6b..9e0ce6b12b1d 100644 --- a/src/util/Util.js +++ b/src/util/Util.js @@ -262,7 +262,7 @@ class Util extends null { */ static fetchRecommendedShards(token, guildsPerShard = 1000) { if (!token) throw new DiscordError('TOKEN_MISSING'); - const defaults = Options.createDefaultOptions(); + const defaults = Options.createDefault(); return fetch(`${defaults.http.api}/v${defaults.http.version}${Endpoints.botGateway}`, { method: 'GET', headers: { Authorization: `Bot ${token.replace(/^Bot\s*/i, '')}` }, From 9a61f197b4471fb4e8f0e9c393804ff7446de4f1 Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Sat, 3 Jul 2021 12:58:59 -0400 Subject: [PATCH 12/14] fix(Manager): use classes directly --- src/managers/ReactionUserManager.js | 3 ++- src/managers/VoiceStateManager.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/managers/ReactionUserManager.js b/src/managers/ReactionUserManager.js index d7e912189f71..68dd07eda312 100644 --- a/src/managers/ReactionUserManager.js +++ b/src/managers/ReactionUserManager.js @@ -2,6 +2,7 @@ const CachedManager = require('./CachedManager'); const { Error } = require('../errors'); +const User = require('../structures/User'); const Collection = require('../util/Collection'); /** @@ -10,7 +11,7 @@ const Collection = require('../util/Collection'); */ class ReactionUserManager extends CachedManager { constructor(reaction, iterable) { - super(reaction.client, { name: 'User' }, iterable); + super(reaction.client, User, iterable); /** * The reaction that this manager belongs to diff --git a/src/managers/VoiceStateManager.js b/src/managers/VoiceStateManager.js index 2dc2db9203d3..d33c5ba72d1f 100644 --- a/src/managers/VoiceStateManager.js +++ b/src/managers/VoiceStateManager.js @@ -1,6 +1,7 @@ 'use strict'; const CachedManager = require('./CachedManager'); +const VoiceState = require('../structures/VoiceState'); /** * Manages API methods for VoiceStates and stores their cache. @@ -8,7 +9,7 @@ const CachedManager = require('./CachedManager'); */ class VoiceStateManager extends CachedManager { constructor(guild, iterable) { - super(guild.client, { name: 'VoiceState' }, iterable); + super(guild.client, VoiceState, iterable); /** * The guild this manager belongs to From e648b9363f4b30a8db469d05123f014395039b87 Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Sat, 3 Jul 2021 12:59:47 -0400 Subject: [PATCH 13/14] refactor(Options): remove cacheNothing --- src/util/Options.js | 9 --------- typings/index.d.ts | 1 - 2 files changed, 10 deletions(-) diff --git a/src/util/Options.js b/src/util/Options.js index 08cde855fc1a..7f00b38daf05 100644 --- a/src/util/Options.js +++ b/src/util/Options.js @@ -155,15 +155,6 @@ class Options extends null { const Collection = require('./Collection'); return () => new Collection(); } - - /** - * Create a cache factory that always caches nothing. - * @returns {CacheFactory} - */ - static cacheNothing() { - const LimitedCollection = require('./LimitedCollection'); - return () => new LimitedCollection(0); - } } module.exports = Options; diff --git a/typings/index.d.ts b/typings/index.d.ts index 4698db0ad289..6ebdee0002af 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -530,7 +530,6 @@ declare module 'discord.js' { public static createDefaultOptions(): ClientOptions; public static cacheWithLimits(limits?: Partial>): CacheFactory; public static cacheEverything(): CacheFactory; - public static cacheNothing(): CacheFactory; } export class ClientVoiceManager { From 8d29c17b9969bd9ba3ec0fe1d823d5552fd6f7bb Mon Sep 17 00:00:00 2001 From: 1Computer1 <22125769+1Computer1@users.noreply.github.com> Date: Sat, 3 Jul 2021 13:00:22 -0400 Subject: [PATCH 14/14] refactor(Options): remove Partial for limits --- src/util/Options.js | 2 +- typings/index.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/Options.js b/src/util/Options.js index 7f00b38daf05..dc8e77810d26 100644 --- a/src/util/Options.js +++ b/src/util/Options.js @@ -131,7 +131,7 @@ class Options extends null { /** * Create a cache factory using predefined limits. - * @param {Partial>} [limits={}] Limits for structures. + * @param {Record} [limits={}] Limits for structures. * @returns {CacheFactory} */ static cacheWithLimits(limits = {}) { diff --git a/typings/index.d.ts b/typings/index.d.ts index 6ebdee0002af..3d2a68890e45 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -528,7 +528,7 @@ declare module 'discord.js' { export class Options { public static createDefaultOptions(): ClientOptions; - public static cacheWithLimits(limits?: Partial>): CacheFactory; + public static cacheWithLimits(limits?: Record): CacheFactory; public static cacheEverything(): CacheFactory; }