@wolfstar/plugin-gateway 0.8.0 → 0.9.0-next-20261002081721

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import { Client, Listener, container } from "@wolfstar/http-framework";
2
2
  import { CloseCodes, DefaultWebSocketManagerOptions, WebSocketManager, WebSocketShardEvents, WebSocketShardStatus } from "@discordjs/ws";
3
3
  import { Client as Client$1 } from "@discordjs/core";
4
- import { applyGatewayDispatch, autoModerationRuleKey, banKey, createCache, emojiKey, integrationKey, inviteKey, isIterableCache, memberKey, mergeValues, messageKey, presenceKey, roleKey, scheduledEventKey, soundboardSoundKey, stageInstanceKey, stickerKey, threadMemberKey, voiceStateKey } from "@wolfstar/plugin-cache";
4
+ import { MemoryEntityCache, applyGatewayDispatch, autoModerationRuleKey, banKey, createCache, emojiKey, integrationKey, inviteKey, isIterableCache, memberKey, messageKey, presenceKey, roleKey, scheduledEventKey, soundboardSoundKey, stageInstanceKey, stickerKey, threadMemberKey, voiceStateKey } from "@wolfstar/plugin-cache";
5
5
  import { ActivityType, ApplicationFlags, AuditLogEvent, ButtonStyle, ChannelType, ComponentType, FormattingPatterns, GatewayDispatchEvents, GatewayIntentBits, GatewayOpcodes, GuildFeature, GuildMemberFlags, GuildPremiumTier, GuildScheduledEventStatus, GuildSystemChannelFlags, GuildWidgetStyle, InviteType, MessageFlags, MessageReferenceType, MessageType, OverwriteType, PermissionFlagsBits, PresenceUpdateStatus, RoleFlags, RouteBases, Routes, SeparatorSpacingSize, StickerFormatType, UserFlags, WebhookType } from "discord-api-types/v10";
6
6
  import { ActionRowComponent, Activity as Activity$1, ActivityFlagsBitField as ActivityFlagsBitField$1, AnnouncementChannel as AnnouncementChannel$1, AnnouncementThreadChannel as AnnouncementThreadChannel$1, Attachment as Attachment$1, AttachmentFlagsBitField as AttachmentFlagsBitField$1, AutoModerationRule as AutoModerationRule$1, BitField, BitField as BitField$1, CategoryChannel as CategoryChannel$1, Channel as Channel$1, ChannelFlagsBitField as ChannelFlagsBitField$1, ChannelSelectMenuComponent as ChannelSelectMenuComponent$1, Component as Component$1, ContainerComponent as ContainerComponent$1, DMChannel as DMChannel$1, Embed as Embed$1, Emoji as Emoji$1, FileComponent as FileComponent$1, FileUploadComponent as FileUploadComponent$1, ForumChannel as ForumChannel$1, GroupDMChannel as GroupDMChannel$1, InteractiveButtonComponent as InteractiveButtonComponent$1, Invite, LinkButtonComponent as LinkButtonComponent$1, MediaChannel as MediaChannel$1, MediaGalleryComponent as MediaGalleryComponent$1, MediaGalleryItem as MediaGalleryItem$1, MentionableSelectMenuComponent as MentionableSelectMenuComponent$1, Message as Message$1, MessageFlagsBitField as MessageFlagsBitField$1, PermissionsBitField, Poll as Poll$1, PollAnswer as PollAnswer$1, PremiumButtonComponent as PremiumButtonComponent$1, Presence as Presence$1, PrivateThreadChannel as PrivateThreadChannel$1, PublicThreadChannel as PublicThreadChannel$1, Reaction, RoleSelectMenuComponent as RoleSelectMenuComponent$1, SectionComponent as SectionComponent$1, SeparatorComponent as SeparatorComponent$1, SoundboardSound as SoundboardSound$1, StageChannel as StageChannel$1, StageInstance as StageInstance$1, Sticker as Sticker$1, StickerPack as StickerPack$1, StringSelectMenuComponent as StringSelectMenuComponent$1, Structure as Structure$1, TextChannel as TextChannel$1, TextDisplayComponent as TextDisplayComponent$1, TextInputComponent as TextInputComponent$1, ThumbnailComponent as ThumbnailComponent$1, UnfurledMediaItem as UnfurledMediaItem$1, User as User$1, UserSelectMenuComponent as UserSelectMenuComponent$1, VoiceChannel as VoiceChannel$1, VoiceState as VoiceState$1, Webhook as Webhook$1 } from "@discordjs/structures";
7
7
  import { CDN, DiscordAPIError } from "@discordjs/rest";
8
8
  import { basename as basename$1, parse, resolve } from "node:path";
9
9
  import { readFile, stat } from "node:fs/promises";
10
+ import { Collection } from "@discordjs/collection";
10
11
  import { randomBytes } from "node:crypto";
11
12
 
12
13
  //#region src/EventGatewayListener.ts
@@ -59,16 +60,19 @@ var EventGatewayListener = class extends Listener {
59
60
  */
60
61
  const GatewayErrorMessages = {
61
62
  ClientSessionStoreConflict: "sessionStore replaces gateway.retrieveSessionInfo and gateway.updateSessionInfo, pass one or the other",
63
+ ClientCacheConflict: "cacheConstructor and cacheOptions cannot be combined with cache or makeCache, pass one or the other",
62
64
  ClientNotConstructed: "No GatewayClient has been constructed yet",
63
65
  DispatchHandlerConflict: (event) => `Dispatch event "${event}" is registered in both DispatchHandlers and MultiDispatchHandlers`,
64
66
  DispatchTimeout: (type, shardId, partition, timeout) => `Processing ${type} on shard ${shardId} (${partition ?? "barrier"}) took longer than ${timeout}ms`,
65
67
  SessionStoreFailed: (operation, shardId) => `Cannot ${operation === "get" ? "read" : "write"} the session of shard ${shardId} in the session store`,
66
68
  SessionStoreTimeout: (timeout) => `Timed out after ${timeout}ms`,
67
- CacheAsynchronous: (entity) => `The ${entity} cache is asynchronous, use get instead of cached`,
68
- CacheRelationsAsynchronous: (entity) => `The relations of the ${entity} cache are read from an asynchronous cache, use get instead of cached`,
69
+ CacheAsynchronous: (entity) => `The ${entity} cache is asynchronous, await cache.get instead`,
70
+ CacheConstructorAsynchronous: (entity) => `The ${entity} structures resolve relations from an asynchronous cache, which a cache of instances cannot await`,
69
71
  CacheNotIterable: (entity) => `The ${entity} cache cannot enumerate its entries (it has no keys/values/entries)`,
70
72
  CacheKeyUnresolvable: (entity, reason) => `Cannot key a ${entity} ${reason}`,
71
73
  IdUnresolvable: "Cannot resolve an ID from a structure without one",
74
+ InvalidType: (name, expected, an = false) => `Supplied ${name} is not a${an ? "n" : ""} ${expected}.`,
75
+ InvalidElement: (type, name, element) => `Supplied ${type} ${name} includes an invalid element: ${String(element)}`,
72
76
  ChannelGuildUnknown: (channelId) => `Channel ${channelId} has no known guild`,
73
77
  ChannelTypeChanged: (channelId, from, to) => `Channel ${channelId} changed type from ${from} to ${to}`,
74
78
  ChannelLockPermissionsConflict: "Pass either lockPermissions or permissionOverwrites, not both",
@@ -88,6 +92,7 @@ const GatewayErrorMessages = {
88
92
  GuildMembersRateLimited: (guildId, nonce, retryAfter) => `Requesting the members of guild ${guildId} (${nonce}) is rate limited, retry after ${retryAfter}ms`,
89
93
  PresenceNotFetchable: (guildId, userId) => `Presences cannot be fetched from the API, they are only received from the gateway (user ${userId} of guild ${guildId} is not cached); enable the presences cache to read them later`,
90
94
  InviteGuildUnknown: (code) => `Invite ${code} has no known guild`,
95
+ UserNoDMChannel: "No DM Channel exists!",
91
96
  EmojiEmpty: "Cannot resolve an empty string to an emoji",
92
97
  EmojiType: "Cannot resolve an emoji without an ID nor a name",
93
98
  NotGuildSticker: "Only guild stickers can be edited or deleted",
@@ -645,6 +650,21 @@ function whenAll(values, callback) {
645
650
  return values.some(isPromiseLike) ? Promise.all(values).then(callback) : callback(values);
646
651
  }
647
652
  /**
653
+ * Resolves the relations of a structure again from its current data, and assigns them to that same structure: what
654
+ * keeps a long-lived instance from holding the relations of the day it was built. Synchronous when `hydrate` is.
655
+ *
656
+ * @param value The structure.
657
+ * @param hydrate Builds a structure of the same data, with its relations.
658
+ * @returns The structure it was given.
659
+ * @internal
660
+ */
661
+ function refreshRelations(value, hydrate) {
662
+ return whenAll([hydrate(value.toJSON())], ([fresh]) => {
663
+ value[kRelations] = fresh[kRelations];
664
+ return value;
665
+ });
666
+ }
667
+ /**
648
668
  * Picks the cached structures of some IDs, in their order, skipping the ones that are not cached: the equivalent of
649
669
  * the collections discord.js fills from its caches, e.g. `MessageMentions#channels`.
650
670
  *
@@ -676,6 +696,17 @@ function whenCachedMap(ids, get) {
676
696
  return map;
677
697
  });
678
698
  }
699
+ /**
700
+ * Reads what a {@link Cache} holds under a key as is: for a cache of instances (a `Map`, e.g. `CollectionCache`), the
701
+ * instance itself, without re-resolving its relations as `get` does. Other caches are read with `get`.
702
+ *
703
+ * @param cache The cache.
704
+ * @param key The key of the entry.
705
+ * @internal
706
+ */
707
+ function peekCache(cache, key) {
708
+ return cache instanceof Map ? Map.prototype.get.call(cache, key) : cache.get(key);
709
+ }
679
710
 
680
711
  //#endregion
681
712
  //#region src/util/Colors.ts
@@ -1019,16 +1050,16 @@ function computePositions(id, position, relative, sorted) {
1019
1050
  */
1020
1051
  function transformResolved({ client, guildId }, { users, members, roles, channels }) {
1021
1052
  return whenAll([
1022
- users && resolveEach(users, (id) => client.users._get(id), (raw) => client.users._resolveData(raw)),
1023
- guildId && members ? resolveEach(members, (id) => client.members._get(guildId, id), (raw) => client.members._resolveData({
1053
+ users && resolveEach(users, (id) => client.users.cache.get(id), (raw) => client.users._resolveData(raw)),
1054
+ guildId && members ? resolveEach(members, (id) => client.members.cache.get(client.members.resolveKey(guildId, id)), (raw) => client.members._resolveData({
1024
1055
  ...raw,
1025
1056
  guild_id: guildId
1026
1057
  }), (raw) => raw.user.id) : void 0,
1027
- guildId && roles ? resolveEach(roles, (id) => client.roles._get(guildId, id), (raw) => client.roles._resolveData({
1058
+ guildId && roles ? resolveEach(roles, (id) => client.roles.cache.get(client.roles.resolveKey(guildId, id)), (raw) => client.roles._resolveData({
1028
1059
  ...raw,
1029
1060
  guild_id: guildId
1030
1061
  })) : void 0,
1031
- channels && resolveEach(channels, (id) => client.channels._get(id), (raw) => client.channels._resolveData(raw))
1062
+ channels && resolveEach(channels, (id) => client.channels.cache.get(id), (raw) => client.channels._resolveData(raw))
1032
1063
  ], ([resolvedUsers, resolvedMembers, resolvedRoles, resolvedChannels]) => {
1033
1064
  const result = {};
1034
1065
  if (resolvedUsers) result.users = resolvedUsers;
@@ -1458,10 +1489,19 @@ var User = class extends User$1 {
1458
1489
  return guild?.identityGuildId && guild.badge ? cdn.guildTagBadge(guild.identityGuildId, guild.badge, options) : null;
1459
1490
  }
1460
1491
  /**
1461
- * Opens a direct message channel with the user, or gets the existing one.
1492
+ * The cached direct message channel with the user, see `UserManager#dmChannel`: `null` when there is none, or when
1493
+ * the channel cache cannot be searched. Synchronous when the channel cache is.
1494
+ */
1495
+ get dmChannel() {
1496
+ return this.client.users.dmChannel(this.id);
1497
+ }
1498
+ /**
1499
+ * Opens a direct message channel with the user, reusing the cached one.
1500
+ *
1501
+ * @param force Whether to skip the cache lookup and always call the API.
1462
1502
  */
1463
- createDM() {
1464
- return this.client.users.createDM(this.id);
1503
+ createDM(force = false) {
1504
+ return this.client.users.createDM(this.id, { force });
1465
1505
  }
1466
1506
  /**
1467
1507
  * Closes the direct message channel with the user.
@@ -2132,13 +2172,27 @@ var PermissionOverwrites = class extends Structure {
2132
2172
  }
2133
2173
  };
2134
2174
 
2175
+ //#endregion
2176
+ //#region src/managers/BaseManager.ts
2177
+ /**
2178
+ * Manages the API methods of a data model, like discord.js's `BaseManager`.
2179
+ */
2180
+ var BaseManager = class {
2181
+ /**
2182
+ * The client that instantiated this manager.
2183
+ */
2184
+ client;
2185
+ constructor(client) {
2186
+ this.client = client;
2187
+ }
2188
+ };
2189
+
2135
2190
  //#endregion
2136
2191
  //#region src/managers/PermissionOverwriteManager.ts
2137
2192
  /**
2138
2193
  * Manages the permission overwrites of one channel, as they were in the channel's payload.
2139
2194
  */
2140
- var PermissionOverwriteManager = class {
2141
- client;
2195
+ var PermissionOverwriteManager = class extends BaseManager {
2142
2196
  channelId;
2143
2197
  guildId;
2144
2198
  #overwrites;
@@ -2151,7 +2205,7 @@ var PermissionOverwriteManager = class {
2151
2205
  * @param channel The channel, which the overwrites refer to.
2152
2206
  */
2153
2207
  constructor(client, channelId, guildId, overwrites, channel = null) {
2154
- this.client = client;
2208
+ super(client);
2155
2209
  this.channelId = channelId;
2156
2210
  this.guildId = guildId;
2157
2211
  this.#overwrites = overwrites;
@@ -2246,16 +2300,13 @@ var PermissionOverwriteManager = class {
2246
2300
  async guessType(target, id) {
2247
2301
  if (typeof target !== "string") return "hoist" in target ? OverwriteType.Role : OverwriteType.Member;
2248
2302
  if (id === this.guildId || !this.guildId) return OverwriteType.Role;
2249
- if (this.client.roles.cache) return await this.client.roles.get(this.guildId, id) ? OverwriteType.Role : OverwriteType.Member;
2303
+ if (this.client.cache?.roles) return await this.client.roles.cache.get(this.client.roles.resolveKey(this.guildId, id)) ? OverwriteType.Role : OverwriteType.Member;
2250
2304
  return (await this.client.roles.fetchAll(this.guildId)).some((role) => role.id === id) ? OverwriteType.Role : OverwriteType.Member;
2251
2305
  }
2252
2306
  async patchCached(update) {
2253
- const cache = this.client.cache?.channels;
2254
- const cached = await cache?.get(this.channelId);
2255
- if (!cached || !("permission_overwrites" in cached)) return;
2256
- await cache.set(this.channelId, {
2257
- ...cached,
2258
- permission_overwrites: update(cached.permission_overwrites ?? [])
2307
+ await this.client.channels._patchCached(this.channelId, (cached) => {
2308
+ const data = cached.toJSON();
2309
+ return "permission_overwrites" in data ? { permission_overwrites: update(data.permission_overwrites ?? []) } : void 0;
2259
2310
  });
2260
2311
  }
2261
2312
  };
@@ -2497,12 +2548,11 @@ var ChannelSlowmodeMixin = class {
2497
2548
  /**
2498
2549
  * Manages the threads of one channel: `client.threads`, with the channel's ID filled in.
2499
2550
  */
2500
- var ChannelThreadManager = class {
2501
- client;
2551
+ var ChannelThreadManager = class extends BaseManager {
2502
2552
  channelId;
2503
2553
  guildId;
2504
2554
  constructor(client, channelId, guildId) {
2505
- this.client = client;
2555
+ super(client);
2506
2556
  this.channelId = channelId;
2507
2557
  this.guildId = guildId;
2508
2558
  }
@@ -2677,18 +2727,17 @@ var GuildChannelMixin = class {
2677
2727
  /**
2678
2728
  * Manages the messages of one channel: `client.messages`, with the channel's ID filled in.
2679
2729
  */
2680
- var ChannelMessageManager = class {
2681
- client;
2730
+ var ChannelMessageManager = class extends BaseManager {
2682
2731
  channelId;
2683
2732
  constructor(client, channelId) {
2684
- this.client = client;
2733
+ super(client);
2685
2734
  this.channelId = channelId;
2686
2735
  }
2687
2736
  /**
2688
2737
  * Gets a message of the channel from the cache.
2689
2738
  */
2690
- get(messageId) {
2691
- return this.client.messages.get(this.channelId, messageId);
2739
+ async get(messageId) {
2740
+ return this.client.messages.cache.get(this.client.messages.resolveKey(this.channelId, messageId));
2692
2741
  }
2693
2742
  /**
2694
2743
  * Gets a message of the channel from the cache, falling back to the API.
@@ -2872,18 +2921,17 @@ var ChannelOwnerMixin = class {
2872
2921
  /**
2873
2922
  * Manages the members of one thread: `client.threadMembers`, with the thread's ID filled in.
2874
2923
  */
2875
- var ThreadChannelMemberManager = class {
2876
- client;
2924
+ var ThreadChannelMemberManager = class extends BaseManager {
2877
2925
  threadId;
2878
2926
  constructor(client, threadId) {
2879
- this.client = client;
2927
+ super(client);
2880
2928
  this.threadId = threadId;
2881
2929
  }
2882
2930
  /**
2883
2931
  * Gets a member of the thread from the cache.
2884
2932
  */
2885
- get(userId) {
2886
- return this.client.threadMembers.get(this.threadId, userId);
2933
+ async get(userId) {
2934
+ return this.client.threadMembers.cache.get(this.client.threadMembers.resolveKey(this.threadId, userId));
2887
2935
  }
2888
2936
  /**
2889
2937
  * Gets a member of the thread from the cache, falling back to the API.
@@ -3687,187 +3735,222 @@ var StageInstance = class extends StageInstance$1 {
3687
3735
  Mixin(StageInstance, [StructureMixin]);
3688
3736
 
3689
3737
  //#endregion
3690
- //#region src/managers/CachedManager.ts
3738
+ //#region src/managers/DataManager.ts
3691
3739
  /**
3692
- * The base class of every manager, the `BaseManager` of the discord.js RFC #11426: it reads raw data from one of the
3693
- * client's entity caches, falls back to the REST API when asked to, and wraps the result in a
3694
- * {@link StructureMixin | structure} with {@link CachedManager.construct}.
3695
- *
3696
- * @remarks
3697
- * The cache only ever holds raw API data, building structures is always the manager's job. Without a store for its
3698
- * entity (see the client's `makeCache`), `get` always resolves to `undefined` and `fetch` always hits the API.
3699
- *
3700
- * A failing store (e.g. Redis being unreachable) emits `cacheError` and, with the client's default
3701
- * `cacheErrors: "miss"`, is treated as a cache miss.
3740
+ * Manages the API methods of a data model along with a collection of instances, like discord.js's `DataManager`.
3702
3741
  *
3703
- * Every method is asynchronous since the cache can be Redis, except {@link CachedManager.cached}, which reads a
3704
- * synchronous cache (`createInMemoryCache`) without awaiting it.
3705
- *
3706
- * Like discord.js's `CachedManager`, every payload coming from the API goes through {@link CachedManager._add}, which
3707
- * patches the cached entry and builds the structure. Structures are built by {@link CachedManager.hydrate}, which
3708
- * resolves their relations (a message's author, a member's user, ...) from the cache, so they carry the latest known
3709
- * data rather than the copy embedded in the payload.
3710
- *
3711
- * @typeParam Name The name of the entity cache this manager reads from.
3712
- * @typeParam Value The structure this manager builds.
3742
+ * @typeParam Value The structure this manager holds.
3713
3743
  * @typeParam Args The arguments identifying an entity, e.g. `[id]` or `[guildId, userId]`.
3714
3744
  */
3715
- var CachedManager = class {
3716
- /**
3717
- * The client this manager belongs to.
3718
- */
3719
- client;
3720
- /**
3721
- * The name of the entity cache this manager reads from.
3722
- */
3723
- entity;
3724
- constructor(client, entity) {
3725
- this.client = client;
3726
- this.entity = entity;
3727
- }
3745
+ var DataManager = class extends BaseManager {
3728
3746
  /**
3729
- * The entity cache this manager reads from, or `undefined` when the client has no cache.
3747
+ * Resolves a structure or a cache key to a structure.
3748
+ *
3749
+ * @param value A structure, returned as is, or the cache key of an entity (its ID, for managers keyed by ID).
3750
+ * @returns The structure, or `null` if the key is not cached.
3730
3751
  */
3731
- get cache() {
3732
- return this.client.cache?.[this.entity];
3752
+ resolve(value) {
3753
+ if (typeof value !== "string") return value ?? null;
3754
+ return whenAll([this.cache.get(value)], ([cached]) => cached ?? null);
3733
3755
  }
3734
3756
  /**
3735
- * Gets an entity from the cache.
3757
+ * Resolves a structure or an ID to an ID.
3736
3758
  *
3737
- * @param args The arguments identifying the entity.
3738
- * @returns The entity, or `undefined` if it is not cached.
3759
+ * @param value A structure, or an ID.
3760
+ * @returns The ID, or `null` if the value is neither.
3739
3761
  */
3740
- async get(...args) {
3741
- return this._get(...args);
3762
+ resolveId(value) {
3763
+ if (typeof value === "string") return value;
3764
+ const id = value?.id;
3765
+ return typeof id === "string" ? id : null;
3742
3766
  }
3767
+ };
3768
+
3769
+ //#endregion
3770
+ //#region src/managers/CachedManager.ts
3771
+ /**
3772
+ * Manages the API methods of a data model with a mutable cache of instances: the `CachedManager` of the discord.js
3773
+ * RFC #11426.
3774
+ *
3775
+ * @remarks
3776
+ * Reads go through {@link CachedManager.cache}: `client.users.cache.get(id)`. The cache is built by the client's
3777
+ * `cacheConstructor` (`CollectionCache` by default) and shared by every manager of the same entity.
3778
+ *
3779
+ * Caches keyed by more than an ID take the key built by `resolveKey`:
3780
+ * `client.members.cache.get(client.members.resolveKey(guildId, userId))`.
3781
+ *
3782
+ * @typeParam Name The name of the entity this manager holds.
3783
+ * @typeParam Value The structure this manager builds.
3784
+ * @typeParam Args The arguments identifying an entity, e.g. `[id]` or `[guildId, userId]`.
3785
+ */
3786
+ var CachedManager = class extends DataManager {
3743
3787
  /**
3744
- * Gets an entity from a synchronous cache, without awaiting it: the synchronous counterpart of
3745
- * {@link CachedManager.get}, for hot paths such as message filters.
3746
- *
3747
- * @remarks
3748
- * It builds the same structure as `get`, relations included, so the entity caches they are read from must be
3749
- * synchronous too, which they all are with `createInMemoryCache`. `manager.cache?.synchronous` tells whether it can
3750
- * be called.
3751
- *
3752
- * An asynchronous cache throws rather than returning `undefined`: it cannot tell whether the entity is cached, and
3753
- * reporting a miss would silently skip whatever the caller does with cached entities, e.g. a filter.
3788
+ * The cache of this manager's entity.
3754
3789
  *
3755
3790
  * @example
3756
3791
  * ```typescript
3757
- * const member = client.members.cached(guildId, userId);
3792
+ * const user = await client.users.cache.get(userId);
3758
3793
  * ```
3759
- *
3760
- * @param args The arguments identifying the entity.
3761
- * @returns The entity, or `undefined` if it is not cached or the client has no cache.
3762
- * @throws {TypeError} When the entity cache, or one of the caches its relations are read from, is asynchronous.
3763
3794
  */
3764
- cached(...args) {
3765
- const { cache } = this;
3766
- if (cache === void 0) return void 0;
3767
- if (cache.synchronous !== true) throw new GatewayTypeError("CacheAsynchronous", this.entity);
3768
- const value = this._get(...args);
3769
- if (isPromiseLike(value)) {
3770
- value.catch(() => void 0);
3771
- throw new GatewayTypeError("CacheRelationsAsynchronous", this.entity);
3772
- }
3773
- return value;
3795
+ cache;
3796
+ /**
3797
+ * The name of the entity this manager holds.
3798
+ */
3799
+ name;
3800
+ constructor(client, name) {
3801
+ super(client);
3802
+ this.name = name;
3803
+ this.cache = this.createCache();
3774
3804
  }
3775
3805
  /**
3776
- * Gets an entity from the cache, synchronously when every cache it reads is: the {@link Awaitable} counterpart of
3777
- * {@link CachedManager.get}, which both `get` and {@link CachedManager.cached} rely on.
3778
- *
3779
- * @param args The arguments identifying the entity.
3780
- * @internal
3806
+ * Gets {@link CachedManager.cache} from the client. Managers whose entity spans several caches override it.
3781
3807
  */
3782
- _get(...args) {
3783
- return this.getByKey(this.resolveKey(...args));
3808
+ createCache() {
3809
+ return this.client.CacheConstructor((data) => this.createStructure(data), this.name);
3784
3810
  }
3785
3811
  /**
3786
- * Resolves a structure or a cache key to a structure, like discord.js's `DataManager#resolve`.
3787
- *
3788
- * @param value A structure, returned as is, or the cache key of an entity (its ID, for managers keyed by ID).
3789
- * @returns The structure, or `null` if the key is not cached.
3812
+ * The raw store of this manager's entity, or `undefined` when it is not cached.
3790
3813
  */
3791
- async resolve(value) {
3792
- if (typeof value !== "string") return value;
3793
- return await this.getByKey(value) ?? null;
3814
+ get rawStore() {
3815
+ return this.client.cache?.[this.name];
3794
3816
  }
3795
3817
  /**
3796
- * Adds an API payload to the cache, patching the cached entry with it, and builds its structure. The counterpart of
3797
- * discord.js's `CachedManager#_add`, asynchronous since the cache can be remote.
3818
+ * Adds an API payload to the cache and returns its structure, as in the RFC.
3798
3819
  *
3799
3820
  * @remarks
3800
- * Like discord.js's `_patch`, the payload is shallowly merged into the cached entry, so the fields a partial payload
3801
- * lacks keep their cached value. With `cache` set to `false`, the merged entry is built but not written.
3821
+ * The payload is written with `cache.add`: a cached entry is patched and returned, and with a cache of instances
3822
+ * (`CollectionCache`) that is the very instance the application may already hold. An entity that is not cached is
3823
+ * built and stored.
3802
3824
  *
3803
- * The merge is a read followed by a write, not an atomic operation: on a shared cache, a write landing in between
3804
- * (another process, or a dispatch outside the guild's queue) is overwritten. `@wolfstar/plugin-cache` merges partial
3805
- * dispatches the same way, and the fields at stake are refreshed by the next payload of the entity.
3825
+ * With `cache` set to `false`, a patched clone is returned (or the entity is built) and the cache is left
3826
+ * untouched. The same goes for an entry the `filter` of the entity's policy rejects, whose cached entry is deleted
3827
+ * on top of that: a rejected update must not leave the outdated entry behind.
3806
3828
  *
3807
3829
  * @param data The raw data.
3808
- * @param cache Whether to write the merged entry to the cache.
3809
- * @param options The cache key, when it cannot be derived from the data.
3830
+ * @param cache Whether to write to the cache.
3831
+ * @param options The cache key, when it cannot be derived from the data, and the extras of `createStructure`.
3810
3832
  * @internal
3811
3833
  */
3812
- async _add(data, cache = true, { key = this.keyOf(data) } = {}) {
3813
- const store = this.cache;
3814
- if (store === void 0) return this.hydrate(data);
3815
- if (!cache) {
3816
- const existing = await this.guard("get", key, () => store.get(key), void 0);
3817
- return this.hydrate(mergeValues(existing, data));
3834
+ async _add(data, cache = true, { id, extras = [] } = {}) {
3835
+ const derived = id === void 0 ? this.keyOf(data) : this.derivedKey(data);
3836
+ const key = id ?? derived;
3837
+ if (!cache) return this.detached(await this.cache.get(key), data, extras);
3838
+ if (this.client.cacheFilter(this.name)) {
3839
+ const existing = await this.cache.get(key);
3840
+ if (!this.accepts(key, existing, data)) {
3841
+ if (existing) await this.cache.delete(key);
3842
+ return this.detached(existing, data, extras);
3843
+ }
3818
3844
  }
3819
- const { added } = await this.guard("upsert", key, () => store.upsert(key, data), { added: data });
3820
- return this.hydrate(added);
3845
+ if (key === derived && extras.length === 0) return this.cache.add(data);
3846
+ const existing = await this.cache.get(key);
3847
+ if (existing) {
3848
+ existing[kPatch](data);
3849
+ await this.cache.set(key, existing);
3850
+ return this.resolveRelations(existing, extras);
3851
+ }
3852
+ const entry = await this._build(data, extras);
3853
+ await this.cache.set(key, entry);
3854
+ return entry;
3821
3855
  }
3822
3856
  /**
3823
- * Gets the cached structure of the entity raw data describes, or builds one from the data when it is not cached.
3824
- * Used to resolve the relations of other structures, e.g. a message's author.
3857
+ * Patches the cached entry of a key, if any, with the fields an endpoint answered without the entity itself.
3825
3858
  *
3826
- * @param data The raw data.
3859
+ * @remarks
3860
+ * Like every write of the managers, it follows the `filter` of the entity's policy: an entry whose patched data is
3861
+ * rejected is deleted from the cache.
3862
+ *
3863
+ * @param key The cache key of the entry.
3864
+ * @param patch The fields to patch, or a function computing them from the cached entry, `undefined` to leave it.
3865
+ * @internal
3827
3866
  */
3828
- async resolveData(data) {
3829
- return this._resolveData(data);
3867
+ async _patchCached(key, patch) {
3868
+ const cached = await this.cache.get(key);
3869
+ if (!cached) return;
3870
+ const data = typeof patch === "function" ? patch(cached) : patch;
3871
+ if (data === void 0) return;
3872
+ if (!this.accepts(key, cached, data)) {
3873
+ await this.cache.delete(key);
3874
+ return;
3875
+ }
3876
+ cached[kPatch](data);
3877
+ await this.cache.set(key, cached);
3878
+ }
3879
+ accepts(key, existing, data) {
3880
+ const filter = this.client.cacheFilter(this.name);
3881
+ if (!filter) return true;
3882
+ const cached = existing?.toJSON();
3883
+ return filter(cached ? {
3884
+ ...cached,
3885
+ ...data
3886
+ } : data, key);
3887
+ }
3888
+ detached(existing, data, extras) {
3889
+ return existing ? this.resolveRelations(existing[kClone](data), extras) : this._build(data, extras);
3890
+ }
3891
+ derivedKey(data) {
3892
+ try {
3893
+ return this.keyOf(data);
3894
+ } catch {
3895
+ return;
3896
+ }
3897
+ }
3898
+ resolveRelations(value, extras) {
3899
+ return refreshRelations(value, (data) => this._build(data, extras));
3830
3900
  }
3831
3901
  /**
3832
- * The {@link Awaitable} counterpart of {@link CachedManager.resolveData}, synchronous when every cache it reads is.
3902
+ * Gets the cached structure of the entity raw data describes, or builds one from the data when it is not cached.
3903
+ * Used to resolve the relations of other structures, e.g. a message's author. Synchronous when the cache is.
3833
3904
  *
3834
3905
  * @param data The raw data.
3835
3906
  * @internal
3836
3907
  */
3837
3908
  _resolveData(data) {
3838
- return whenAll([this.getByKey(this.keyOf(data))], ([cached]) => cached ?? this.build(data));
3909
+ return whenAll([this.cache.get(this.keyOf(data))], ([cached]) => cached ?? this._build(data));
3839
3910
  }
3840
3911
  /**
3841
3912
  * Gets a guild from the cache, to resolve the `guild` of a structure. Synchronous when the guild cache is.
3842
3913
  *
3843
- * @param guildId The ID of the guild, if the structure belongs to one.
3844
3914
  * @remarks
3845
3915
  * The guild does not resolve its own channel relations, see `GuildManager._getShallow`.
3846
3916
  *
3917
+ * @param guildId The ID of the guild, if the structure belongs to one.
3847
3918
  * @returns The guild, or `null` when there is no ID or the guild is not cached.
3848
3919
  */
3849
3920
  cachedGuild(guildId) {
3850
3921
  return guildId ? whenAll([this.client.guilds._getShallow(guildId)], ([guild]) => guild ?? null) : null;
3851
3922
  }
3852
3923
  /**
3853
- * Builds the structure of raw data, resolving its relations from the cache. Without relations to resolve, the same
3854
- * as {@link CachedManager.construct}.
3924
+ * Builds the structure of raw data, resolving its relations from the cache; synchronous when every cache the
3925
+ * relations are read from is. Without relations to resolve, the same as `createStructure`.
3855
3926
  *
3856
3927
  * @param data The raw data.
3928
+ * @param extras The extra arguments passed to {@link CachedManager._add}.
3929
+ * @internal
3857
3930
  */
3858
- async hydrate(data) {
3859
- return this.build(data);
3931
+ _hydrate(data, ...extras) {
3932
+ return this.createStructure(data, ...extras);
3860
3933
  }
3861
3934
  /**
3862
- * The {@link Awaitable} counterpart of {@link CachedManager.hydrate}, synchronous when every cache the relations
3863
- * are read from is. Managers resolving relations override this one, so `hydrate` and
3864
- * {@link CachedManager.cached} build the same structures.
3935
+ * Wraps raw data in this manager's structure, bound to this manager's client, without resolving its relations: the
3936
+ * creator handed to this entity's cache, always synchronous.
3865
3937
  *
3866
3938
  * @param data The raw data.
3939
+ * @param extras The extra arguments passed to {@link CachedManager._add}.
3867
3940
  * @internal
3868
3941
  */
3869
- _hydrate(data) {
3870
- return this.construct(data);
3942
+ _construct(data, ...extras) {
3943
+ return bindClient(this.createStructure(data, ...extras), this.client);
3944
+ }
3945
+ /**
3946
+ * Builds the structure of raw data with {@link CachedManager._hydrate}, bound to this manager's client.
3947
+ *
3948
+ * @param data The raw data.
3949
+ * @param extras The extra arguments passed to {@link CachedManager._add}.
3950
+ * @internal
3951
+ */
3952
+ _build(data, extras = []) {
3953
+ return whenAll([this._hydrate(data, ...extras)], ([value]) => bindClient(value, this.client));
3871
3954
  }
3872
3955
  /**
3873
3956
  * Gets an entity from the cache, fetching it from the API (and caching it) on a cache miss.
@@ -3884,12 +3967,13 @@ var CachedManager = class {
3884
3967
  async fetch(...args) {
3885
3968
  const ids = args.slice(0, this.resolveKey.length);
3886
3969
  const { force = false, cache = true } = args[this.resolveKey.length] ?? {};
3970
+ const id = this.resolveKey(...ids);
3887
3971
  if (!force) {
3888
- const cached = await this.get(...ids);
3972
+ const cached = await this.cache.get(id);
3889
3973
  if (cached) return cached;
3890
3974
  }
3891
3975
  const raw = await this.fetchRaw(...ids);
3892
- return this._add(raw, cache, { key: this.resolveKey(...ids) });
3976
+ return this._add(raw, cache, { id });
3893
3977
  }
3894
3978
  /**
3895
3979
  * Fetches an entity from the API, bypassing and then updating the cache. Same as `fetch(...args, { force: true })`.
@@ -3900,78 +3984,23 @@ var CachedManager = class {
3900
3984
  return this.fetch(...args, { force: true });
3901
3985
  }
3902
3986
  /**
3903
- * Wraps raw data in this manager's structure.
3904
- *
3905
- * @param data The raw data.
3906
- * @deprecated Use {@link CachedManager.construct}.
3907
- */
3908
- createStructure(data) {
3909
- return this.construct(data);
3910
- }
3911
- /**
3912
- * Writes raw data to the cache.
3913
- *
3914
- * @param key The cache key of the entity.
3915
- * @param raw The raw data of the entity.
3916
- */
3917
- async storeRaw(key, raw) {
3918
- const { cache } = this;
3919
- if (cache) await this.guard("set", key, () => cache.set(key, raw), void 0);
3920
- }
3921
- /**
3922
- * Gets this manager's store when it can enumerate its entries, for the `listCached` methods.
3987
+ * Gets this entity's raw store when it can enumerate its entries, for the `listCached` methods.
3923
3988
  *
3924
3989
  * @returns The store, or `undefined` when this entity is not cached.
3925
3990
  * @throws {TypeError} When the store cannot enumerate its entries.
3926
3991
  */
3927
3992
  iterableCache() {
3928
- const { cache } = this;
3929
- if (cache === void 0) return void 0;
3930
- if (!isIterableCache(cache)) throw new GatewayTypeError("CacheNotIterable", this.entity);
3931
- return cache;
3932
- }
3933
- /**
3934
- * Gets an entity from the cache by its key, synchronously when every cache it reads is.
3935
- *
3936
- * @param key The cache key of the entity.
3937
- */
3938
- getByKey(key) {
3939
- const { cache } = this;
3940
- return whenAll([cache ? this.guard("get", key, () => cache.get(key), void 0) : void 0], ([raw]) => raw === void 0 ? void 0 : this.build(raw));
3993
+ const store = this.rawStore;
3994
+ if (store === void 0) return void 0;
3995
+ if (!isIterableCache(store)) throw new GatewayTypeError("CacheNotIterable", this.name);
3996
+ return store;
3941
3997
  }
3942
3998
  /**
3943
- * Runs a cache operation, reporting its failure through `cacheError`. With the client's `cacheErrors: "miss"`, a
3944
- * failure resolves to `fallback`, otherwise it is rethrown. Synchronous when the operation is.
3945
- *
3946
- * @param operation The operation, for `cacheError`.
3947
- * @param key The key of the entry, for `cacheError`.
3948
- * @param run Runs the operation.
3949
- * @param fallback What a failure resolves to under `cacheErrors: "miss"`.
3999
+ * Runs a raw store operation, reporting its failure through `cacheError`. With the client's `cacheErrors: "miss"`,
4000
+ * a failure resolves to `fallback`, otherwise it is rethrown. Synchronous when the operation is.
3950
4001
  */
3951
4002
  guard(operation, key, run, fallback) {
3952
- const fail = (error) => {
3953
- this.client.emit("cacheError", error, {
3954
- entity: this.entity,
3955
- key,
3956
- operation
3957
- });
3958
- if (this.client.cacheErrors === "throw") throw error;
3959
- return fallback;
3960
- };
3961
- try {
3962
- const result = run();
3963
- return isPromiseLike(result) ? result.catch(fail) : result;
3964
- } catch (error) {
3965
- return fail(error);
3966
- }
3967
- }
3968
- /**
3969
- * Builds the structure of raw data with {@link CachedManager._hydrate}, bound to this manager's client.
3970
- *
3971
- * @param data The raw data.
3972
- */
3973
- build(data) {
3974
- return whenAll([this._hydrate(data)], ([value]) => bindClient(value, this.client));
4003
+ return this.client.guardCache(this.name, operation, key, run, fallback);
3975
4004
  }
3976
4005
  };
3977
4006
 
@@ -4007,17 +4036,59 @@ function channelGuildId(data) {
4007
4036
  return "guild_id" in data ? data.guild_id ?? void 0 : void 0;
4008
4037
  }
4009
4038
  /**
4039
+ * The cache of {@link ChannelManager}: the channel cache, falling back to the thread cache.
4040
+ */
4041
+ var ChannelCache = class {
4042
+ #channels;
4043
+ #threads;
4044
+ constructor(channels, threads) {
4045
+ this.#channels = channels;
4046
+ this.#threads = threads;
4047
+ }
4048
+ get synchronous() {
4049
+ return this.#channels.synchronous && this.#threads().synchronous;
4050
+ }
4051
+ get construct() {
4052
+ return this.#channels.construct;
4053
+ }
4054
+ add(data, overwrite = false) {
4055
+ return data.type !== void 0 && isThreadChannelType(data.type) ? this.#threads().add(data, overwrite) : this.#channels.add(data, overwrite);
4056
+ }
4057
+ set(key, value) {
4058
+ const target = isThreadChannelType(value.type) ? this.#threads() : this.#channels;
4059
+ return whenAll([target.set(key, value)], () => this);
4060
+ }
4061
+ get(key) {
4062
+ return whenAll([this.#channels.get(key)], ([channel]) => channel ?? this.#threads().get(key));
4063
+ }
4064
+ has(key) {
4065
+ return whenAll([this.#channels.has(key)], ([has]) => has || this.#threads().has(key));
4066
+ }
4067
+ delete(key) {
4068
+ return whenAll([this.#channels.delete(key)], ([deleted]) => deleted || this.#threads().delete(key));
4069
+ }
4070
+ getSize() {
4071
+ return whenAll([this.#channels.getSize(), this.#threads().getSize()], ([a, b]) => a + b);
4072
+ }
4073
+ clear() {
4074
+ return whenAll([this.#channels.clear(), this.#threads().clear()], () => void 0);
4075
+ }
4076
+ };
4077
+ /**
4010
4078
  * Manages the channels known to the client, threads included.
4011
4079
  *
4012
4080
  * @remarks
4013
- * Threads live in their own entity cache, managed by `client.threads`, which {@link ChannelManager.get} falls back
4081
+ * Threads live in their own entity cache, managed by `client.threads`, which {@link ChannelManager.cache} falls back
4014
4082
  * to, so a thread ID resolves like any other channel ID.
4015
4083
  */
4016
4084
  var ChannelManager = class extends CachedManager {
4017
4085
  constructor(client) {
4018
4086
  super(client, "channels");
4019
4087
  }
4020
- construct(data) {
4088
+ createCache() {
4089
+ return new ChannelCache(super.createCache(), () => this.client.threads.cache);
4090
+ }
4091
+ createStructure(data) {
4021
4092
  return createChannel(data);
4022
4093
  }
4023
4094
  keyOf(data) {
@@ -4044,11 +4115,13 @@ var ChannelManager = class extends CachedManager {
4044
4115
  const recipient = data.type === ChannelType.DM ? data.recipients?.[0] : void 0;
4045
4116
  const guildId = channelGuildId(data) ?? guild?.id;
4046
4117
  const thread = isThreadChannelType(data.type);
4118
+ const stageKey = data.type === ChannelType.GuildStageVoice && guildId ? stageInstanceKey(guildId, data.id) : null;
4119
+ const meKey = thread ? threadMemberKey(data.id, client.user?.id ?? client.id) : null;
4047
4120
  return whenAll([
4048
- parentId && depth < MaxParentDepth ? this.cache?.get(parentId) : void 0,
4121
+ parentId && depth < MaxParentDepth ? this.readRaw(parentId) : void 0,
4049
4122
  recipient ? client.users._resolveData(recipient) : void 0,
4050
- data.type === ChannelType.GuildStageVoice && guildId ? client.cache?.stageInstances?.get(stageInstanceKey(guildId, data.id)) : void 0,
4051
- thread ? client.cache?.threadMembers?.get(threadMemberKey(data.id, client.user?.id ?? client.id)) : void 0
4123
+ stageKey ? client.guardCache("stageInstances", "get", stageKey, () => client.cache?.stageInstances?.get(stageKey), void 0) : void 0,
4124
+ meKey ? client.guardCache("threadMembers", "get", meKey, () => client.cache?.threadMembers?.get(meKey), void 0) : void 0
4052
4125
  ], ([parentData, resolvedRecipient, stageData, me]) => whenAll([parentData ? this._hydrateInGuild(parentData, guild, depth + 1) : null], ([parent]) => {
4053
4126
  const relations = {
4054
4127
  guild,
@@ -4072,7 +4145,30 @@ var ChannelManager = class extends CachedManager {
4072
4145
  * @internal
4073
4146
  */
4074
4147
  _getInGuild(channelId, guild) {
4075
- return whenAll([this.cache?.get(channelId)], ([data]) => data ? this._hydrateInGuild(data, guild) : null);
4148
+ return whenAll([this.readRaw(channelId)], ([data]) => data ? this._hydrateInGuild(data, guild) : null);
4149
+ }
4150
+ /**
4151
+ * Finds the cached direct message channel with a user, for `client.users`.
4152
+ *
4153
+ * @remarks
4154
+ * Only a synchronous channel cache that can enumerate its entries is searched: scanning every channel of a remote
4155
+ * store costs more than asking Discord for the channel.
4156
+ *
4157
+ * @param userId The ID of the user.
4158
+ * @returns The channel, `null` when the cache was searched and holds none, `undefined` when it cannot be searched.
4159
+ * @internal
4160
+ */
4161
+ _findDM(userId) {
4162
+ const store = this.rawStore;
4163
+ if (store === void 0 || store.synchronous !== true || !isIterableCache(store)) return;
4164
+ return whenAll([this.guard("entries", null, () => store.entries(), [])], ([entries]) => {
4165
+ const found = entries.find(([, data]) => data.type === ChannelType.DM && data.recipients?.[0]?.id === userId);
4166
+ if (!found) return null;
4167
+ return whenAll([this.cache.get(found[0])], ([channel]) => channel ?? null);
4168
+ });
4169
+ }
4170
+ readRaw(channelId) {
4171
+ return this.guard("get", channelId, () => this.rawStore?.get(channelId), void 0);
4076
4172
  }
4077
4173
  resolveKey(channelId) {
4078
4174
  return channelId;
@@ -4086,25 +4182,6 @@ var ChannelManager = class extends CachedManager {
4086
4182
  return isThreadChannelType(data.type) ? this.client.threads._add(data, cache, options) : super._add(data, cache, options);
4087
4183
  }
4088
4184
  /**
4089
- * Gets a channel from the cache, looking it up in the thread cache as well, which `get` and `cached` rely on.
4090
- *
4091
- * @param channelId The ID of the channel.
4092
- * @internal
4093
- */
4094
- _get(channelId) {
4095
- return whenAll([super._get(channelId)], ([channel]) => channel ?? this.client.threads._get(channelId));
4096
- }
4097
- /**
4098
- * Writes a channel to the cache, threads to the thread cache.
4099
- *
4100
- * @param channelId The ID of the channel.
4101
- * @param raw The raw channel.
4102
- */
4103
- async storeRaw(channelId, raw) {
4104
- if (isThreadChannelType(raw.type)) await this.client.cache?.threads?.set(channelId, raw);
4105
- else await this.cache?.set(channelId, raw);
4106
- }
4107
- /**
4108
4185
  * Edits a channel.
4109
4186
  *
4110
4187
  * @param channelId The ID of the channel.
@@ -4391,9 +4468,13 @@ var Guild = class extends AnonymousGuild {
4391
4468
  const resolved = this[kRelations][name];
4392
4469
  if (resolved !== void 0) return resolved;
4393
4470
  const channelId = this[kData][GuildChannelFields[name]];
4394
- if (!channelId || this.client.cache?.channels?.synchronous !== true) return null;
4471
+ const { cache } = this.client.channels;
4472
+ if (!channelId || !cache.synchronous) return null;
4395
4473
  try {
4396
- return this.client.channels.cached(channelId) ?? null;
4474
+ const channel = cache.get(channelId);
4475
+ if (!isPromiseLike(channel)) return channel ?? null;
4476
+ channel.catch(() => void 0);
4477
+ return null;
4397
4478
  } catch {
4398
4479
  return null;
4399
4480
  }
@@ -6125,8 +6206,12 @@ function changesReduce(changes, initial = {}) {
6125
6206
  }
6126
6207
  return data;
6127
6208
  }
6128
- async function read(value) {
6129
- return value.catch(() => void 0);
6209
+ async function read(manager, ...args) {
6210
+ try {
6211
+ return await manager.cache.get(manager.resolveKey(...args));
6212
+ } catch {
6213
+ return;
6214
+ }
6130
6215
  }
6131
6216
  /**
6132
6217
  * Resolves the target of an audit log entry from the cache, like discord.js's `GuildAuditLogsEntry#target`.
@@ -6144,19 +6229,19 @@ async function resolveAuditLogTarget(client, entry, entities = {}) {
6144
6229
  const { guilds } = client;
6145
6230
  const built = (value) => bindClient(value, client);
6146
6231
  if (type === "Unknown") return changesReduce(changes, { id: targetId });
6147
- const user = async (userId) => entities.users?.get(userId) ?? await read(client.users.get(userId)) ?? null;
6232
+ const user = async (userId) => entities.users?.get(userId) ?? await read(client.users, userId) ?? null;
6148
6233
  if (type === "User") return targetId ? user(targetId) : null;
6149
6234
  if (!targetId && type !== "Invite") return null;
6150
6235
  const id = targetId;
6151
6236
  switch (type) {
6152
- case "Guild": return await read(guilds.get(id)) ?? { id };
6237
+ case "Guild": return await read(guilds, id) ?? { id };
6153
6238
  case "Channel":
6154
- case "Thread": return await read(client.channels.get(id)) ?? changesReduce(changes, { id });
6155
- case "Role": return await read(client.roles.get(guildId, id)) ?? { id };
6239
+ case "Thread": return await read(client.channels, id) ?? changesReduce(changes, { id });
6240
+ case "Role": return await read(client.roles, guildId, id) ?? { id };
6156
6241
  case "Invite": {
6157
6242
  const { id: _id, ...changed } = changesReduce(changes);
6158
6243
  const code = changed.code;
6159
- return (code ? await read(guilds.invites(guildId).get(code)) : void 0) ?? built(new GuildInvite({
6244
+ return (code ? await read(guilds.invites(guildId), code) : void 0) ?? built(new GuildInvite({
6160
6245
  ...changed,
6161
6246
  code: code ?? "",
6162
6247
  guild_id: guildId
@@ -6166,28 +6251,28 @@ async function resolveAuditLogTarget(client, entry, entities = {}) {
6166
6251
  id,
6167
6252
  guild_id: guildId
6168
6253
  })));
6169
- case "Emoji": return await read(guilds.emojis(guildId).get(id)) ?? { id };
6170
- case "Message": return entry.action_type === AuditLogEvent.MessageBulkDelete ? await read(client.channels.get(id)) ?? { id } : user(id);
6171
- case "Integration": return entities.integrations?.get(id) ?? await read(guilds.integrations(guildId).get(id)) ?? built(new Integration(changesReduce(changes, {
6254
+ case "Emoji": return await read(guilds.emojis(guildId), id) ?? { id };
6255
+ case "Message": return entry.action_type === AuditLogEvent.MessageBulkDelete ? await read(client.channels, id) ?? { id } : user(id);
6256
+ case "Integration": return entities.integrations?.get(id) ?? await read(guilds.integrations(guildId), id) ?? built(new Integration(changesReduce(changes, {
6172
6257
  id,
6173
6258
  guild_id: guildId
6174
6259
  })));
6175
6260
  case "StageInstance": {
6176
6261
  const channelId = options?.channel_id;
6177
- return (channelId ? await read(guilds.stageInstances(guildId).get(channelId)) : void 0) ?? built(new StageInstance(changesReduce(changes, {
6262
+ return (channelId ? await read(guilds.stageInstances(guildId), channelId) : void 0) ?? built(new StageInstance(changesReduce(changes, {
6178
6263
  id,
6179
6264
  channel_id: channelId,
6180
6265
  guild_id: guildId
6181
6266
  })));
6182
6267
  }
6183
- case "Sticker": return await read(guilds.stickers(guildId).get(id)) ?? built(new Sticker(changesReduce(changes, { id })));
6184
- case "GuildScheduledEvent": return await read(guilds.scheduledEvents(guildId).get(id)) ?? built(new GuildScheduledEvent(changesReduce(changes, {
6268
+ case "Sticker": return await read(guilds.stickers(guildId), id) ?? built(new Sticker(changesReduce(changes, { id })));
6269
+ case "GuildScheduledEvent": return await read(guilds.scheduledEvents(guildId), id) ?? built(new GuildScheduledEvent(changesReduce(changes, {
6185
6270
  id,
6186
6271
  guild_id: guildId
6187
6272
  })));
6188
6273
  case "ApplicationCommand": return entities.applicationCommands?.get(id) ?? { id };
6189
- case "SoundboardSound": return await read(guilds.soundboardSounds(guildId).get(id)) ?? { id };
6190
- case "AutoModeration": return await read(guilds.autoModerationRules(guildId).get(id)) ?? built(new AutoModerationRule(changesReduce(changes, {
6274
+ case "SoundboardSound": return await read(guilds.soundboardSounds(guildId), id) ?? { id };
6275
+ case "AutoModeration": return await read(guilds.autoModerationRules(guildId), id) ?? built(new AutoModerationRule(changesReduce(changes, {
6191
6276
  id,
6192
6277
  guild_id: guildId
6193
6278
  })));
@@ -6196,59 +6281,146 @@ async function resolveAuditLogTarget(client, entry, entities = {}) {
6196
6281
  }
6197
6282
  }
6198
6283
 
6284
+ //#endregion
6285
+ //#region src/util/roles.ts
6286
+ /**
6287
+ * Whether a value is several roles rather than a single one.
6288
+ *
6289
+ * @internal
6290
+ */
6291
+ function isRoleResolvables(value) {
6292
+ return Array.isArray(value) || value instanceof Collection;
6293
+ }
6294
+ /**
6295
+ * Resolves a role or an ID to an ID.
6296
+ *
6297
+ * @returns The ID, or `null` if the value is neither.
6298
+ * @internal
6299
+ */
6300
+ function resolveRoleId(role) {
6301
+ if (typeof role === "string") return role;
6302
+ const id = role?.id;
6303
+ return typeof id === "string" ? id : null;
6304
+ }
6305
+ /**
6306
+ * Resolves several roles to their IDs, without duplicates.
6307
+ *
6308
+ * @param roles The roles.
6309
+ * @throws {GatewayTypeError} `InvalidElement` when an element is neither a role nor an ID.
6310
+ * @internal
6311
+ */
6312
+ function resolveRoleIds(roles) {
6313
+ const ids = /* @__PURE__ */ new Set();
6314
+ for (const role of roles.values()) {
6315
+ const id = resolveRoleId(role);
6316
+ if (id === null) throw new GatewayTypeError("InvalidElement", "Array or Collection", "roles", role);
6317
+ ids.add(id);
6318
+ }
6319
+ return [...ids];
6320
+ }
6321
+ /**
6322
+ * Reads the cached roles of some IDs into a `Collection`, skipping the ones that are not cached. Synchronous when
6323
+ * the role cache is.
6324
+ *
6325
+ * @param client The client.
6326
+ * @param guildId The ID of the guild of the roles.
6327
+ * @param ids The IDs of the roles.
6328
+ * @internal
6329
+ */
6330
+ function cachedRoles(client, guildId, ids) {
6331
+ const { roles } = client;
6332
+ return whenAll([whenCachedMap(ids, (id) => roles.cache.get(roles.resolveKey(guildId, id)))], ([cached]) => new Collection(cached));
6333
+ }
6334
+
6199
6335
  //#endregion
6200
6336
  //#region src/managers/GuildEmojiRoleManager.ts
6201
6337
  /**
6202
- * Manages the roles allowed to use one custom emoji. When it has none, everyone can use it.
6338
+ * Manages the roles allowed to use one custom emoji, like discord.js's `GuildEmojiRoleManager`. When it has none,
6339
+ * everyone can use it.
6340
+ *
6341
+ * @remarks
6342
+ * {@link GuildEmojiRoleManager.cache} is `Awaitable`, unlike discord.js's: synchronous with the default in-memory
6343
+ * cache, a promise with a remote store.
6203
6344
  */
6204
- var GuildEmojiRoleManager = class {
6205
- client;
6206
- guildId;
6207
- emojiId;
6208
- #roleIds;
6209
- constructor(client, guildId, emojiId, roleIds) {
6210
- this.client = client;
6211
- this.guildId = guildId;
6212
- this.emojiId = emojiId;
6213
- this.#roleIds = roleIds;
6345
+ var GuildEmojiRoleManager = class GuildEmojiRoleManager extends BaseManager {
6346
+ /**
6347
+ * The emoji these roles belong to.
6348
+ */
6349
+ emoji;
6350
+ /**
6351
+ * @param emoji The emoji.
6352
+ */
6353
+ constructor(emoji) {
6354
+ super(emoji.client);
6355
+ this.emoji = emoji;
6356
+ }
6357
+ /**
6358
+ * The emoji's guild, from the cache: `null` when it is not cached.
6359
+ */
6360
+ get guild() {
6361
+ return this.emoji.guild;
6362
+ }
6363
+ get guildId() {
6364
+ return this.emoji.guildId;
6365
+ }
6366
+ get emojiId() {
6367
+ return this.emoji.id;
6214
6368
  }
6215
6369
  /**
6216
6370
  * The IDs of the allowed roles.
6217
6371
  */
6218
6372
  get ids() {
6219
- return this.#roleIds;
6373
+ return this.emoji.roleIds;
6374
+ }
6375
+ /**
6376
+ * The allowed roles held in the cache, by ID. Roles that are not cached are skipped: use
6377
+ * {@link GuildEmojiRoleManager.fetch} to get them all.
6378
+ */
6379
+ get cache() {
6380
+ return cachedRoles(this.client, this.guildId, this.ids);
6220
6381
  }
6221
6382
  /**
6222
6383
  * Fetches the allowed roles, cache first.
6223
6384
  */
6224
6385
  fetch() {
6225
- return Promise.all(this.#roleIds.map((id) => this.client.roles.fetch(this.guildId, id)));
6386
+ return Promise.all(this.ids.map((id) => this.client.roles.fetch(this.guildId, id)));
6226
6387
  }
6227
6388
  /**
6228
6389
  * Allows more roles to use the emoji.
6229
6390
  *
6230
- * @param roles The ID of the role, or several IDs.
6391
+ * @param roleOrRoles The role or its ID, or an array or `Collection` of them.
6392
+ * @returns The emoji, patched.
6231
6393
  */
6232
- add(roles) {
6233
- const added = typeof roles === "string" ? [roles] : roles;
6234
- return this.set([.../* @__PURE__ */ new Set([...this.#roleIds, ...added])]);
6394
+ async add(roleOrRoles) {
6395
+ return this.set([.../* @__PURE__ */ new Set([...this.ids, ...this.resolve(roleOrRoles)])]);
6235
6396
  }
6236
6397
  /**
6237
6398
  * Stops allowing roles to use the emoji.
6238
6399
  *
6239
- * @param roles The ID of the role, or several IDs.
6400
+ * @param roleOrRoles The role or its ID, or an array or `Collection` of them.
6401
+ * @returns The emoji, patched.
6240
6402
  */
6241
- remove(roles) {
6242
- const removed = new Set(typeof roles === "string" ? [roles] : roles);
6243
- return this.set(this.#roleIds.filter((id) => !removed.has(id)));
6403
+ async remove(roleOrRoles) {
6404
+ const removed = new Set(this.resolve(roleOrRoles));
6405
+ return this.set(this.ids.filter((id) => !removed.has(id)));
6244
6406
  }
6245
6407
  /**
6246
6408
  * Replaces the allowed roles, everyone when empty.
6247
6409
  *
6248
- * @param roles The IDs of the roles.
6410
+ * @param roles The roles: an array of roles or IDs, or a `Collection` of roles.
6411
+ * @returns The emoji, patched.
6249
6412
  */
6250
6413
  set(roles) {
6251
- return this.client.guilds.emojis(this.guildId).edit(this.emojiId, { roles });
6414
+ return this.emoji.edit({ roles });
6415
+ }
6416
+ /**
6417
+ * Creates another manager of the same emoji's roles.
6418
+ */
6419
+ clone() {
6420
+ return new GuildEmojiRoleManager(this.emoji);
6421
+ }
6422
+ resolve(roleOrRoles) {
6423
+ return resolveRoleIds(isRoleResolvables(roleOrRoles) ? roleOrRoles : [roleOrRoles]);
6252
6424
  }
6253
6425
  };
6254
6426
 
@@ -6313,7 +6485,7 @@ var GuildEmoji = class extends Emoji {
6313
6485
  * The roles allowed to use the emoji.
6314
6486
  */
6315
6487
  get roles() {
6316
- return new GuildEmojiRoleManager(this.client, this.guildId, this.id, this.roleIds);
6488
+ return new GuildEmojiRoleManager(this);
6317
6489
  }
6318
6490
  /**
6319
6491
  * The user who uploaded the emoji, when the payload includes it (it needs `ManageGuildExpressions`).
@@ -6612,7 +6784,7 @@ var AutoModerationRuleManager = class extends CachedManager {
6612
6784
  super(client, "autoModerationRules");
6613
6785
  this.guildId = guildId;
6614
6786
  }
6615
- construct(data) {
6787
+ createStructure(data) {
6616
6788
  return new AutoModerationRule(data);
6617
6789
  }
6618
6790
  keyOf(data) {
@@ -6665,7 +6837,7 @@ var AutoModerationRuleManager = class extends CachedManager {
6665
6837
  */
6666
6838
  async delete(ruleId, reason) {
6667
6839
  await this.client.api.guilds.deleteAutoModerationRule(this.guildId, ruleId, { reason });
6668
- await this.cache?.delete(this.resolveKey(ruleId));
6840
+ await this.cache.delete(this.resolveKey(ruleId));
6669
6841
  }
6670
6842
  async fetchRaw(ruleId) {
6671
6843
  return this.client.api.guilds.getAutoModerationRule(this.guildId, ruleId);
@@ -6744,7 +6916,7 @@ var GuildBanManager = class extends CachedManager {
6744
6916
  super(client, "bans");
6745
6917
  this.guildId = guildId;
6746
6918
  }
6747
- construct(data) {
6919
+ createStructure(data) {
6748
6920
  return new GuildBan(data);
6749
6921
  }
6750
6922
  keyOf(data) {
@@ -6795,7 +6967,7 @@ var GuildBanManager = class extends CachedManager {
6795
6967
  async remove(user, reason) {
6796
6968
  const userId = resolveId(user);
6797
6969
  await this.client.members.unban(this.guildId, userId, reason);
6798
- await this.cache?.delete(this.resolveKey(userId));
6970
+ await this.cache.delete(this.resolveKey(userId));
6799
6971
  }
6800
6972
  /**
6801
6973
  * Bans up to 200 users at once.
@@ -6823,11 +6995,10 @@ var GuildBanManager = class extends CachedManager {
6823
6995
  /**
6824
6996
  * Manages the channels of one guild. Channels are cached by `client.channels`, which this manager writes to.
6825
6997
  */
6826
- var GuildChannelManager = class {
6827
- client;
6998
+ var GuildChannelManager = class extends BaseManager {
6828
6999
  guildId;
6829
7000
  constructor(client, guildId) {
6830
- this.client = client;
7001
+ super(client);
6831
7002
  this.guildId = guildId;
6832
7003
  }
6833
7004
  /**
@@ -6905,7 +7076,7 @@ var GuildChannelManager = class {
6905
7076
  channel: entry.id,
6906
7077
  position: entry.position
6907
7078
  })), options.reason);
6908
- return await this.client.channels.get(id);
7079
+ return await this.client.channels.cache.get(id);
6909
7080
  }
6910
7081
  /**
6911
7082
  * Fetches the channels a channel is sorted with, itself included, and caches them.
@@ -6949,7 +7120,7 @@ var GuildIntegrationManager = class extends CachedManager {
6949
7120
  super(client, "integrations");
6950
7121
  this.guildId = guildId;
6951
7122
  }
6952
- construct(data) {
7123
+ createStructure(data) {
6953
7124
  return new Integration(data);
6954
7125
  }
6955
7126
  keyOf(data) {
@@ -6971,7 +7142,7 @@ var GuildIntegrationManager = class extends CachedManager {
6971
7142
  return whenAll([
6972
7143
  data.user ? this.client.users._resolveData(data.user) : null,
6973
7144
  this.cachedGuild(data.guild_id),
6974
- data.role_id ? this.client.roles._get(data.guild_id, data.role_id) : void 0
7145
+ data.role_id ? this.client.roles.cache.get(this.client.roles.resolveKey(data.guild_id, data.role_id)) : void 0
6975
7146
  ], ([user, guild, role]) => new Integration(data, {
6976
7147
  user,
6977
7148
  guild,
@@ -6993,7 +7164,7 @@ var GuildIntegrationManager = class extends CachedManager {
6993
7164
  */
6994
7165
  async delete(integrationId, reason) {
6995
7166
  await this.client.api.guilds.deleteIntegration(this.guildId, integrationId, { reason });
6996
- await this.cache?.delete(this.resolveKey(integrationId));
7167
+ await this.cache.delete(this.resolveKey(integrationId));
6997
7168
  }
6998
7169
  async fetchRaw(integrationId) {
6999
7170
  const integration = (await this.list()).find(({ id }) => id === integrationId);
@@ -7019,7 +7190,7 @@ var GuildScheduledEventManager = class extends CachedManager {
7019
7190
  super(client, "scheduledEvents");
7020
7191
  this.guildId = guildId;
7021
7192
  }
7022
- construct(data) {
7193
+ createStructure(data) {
7023
7194
  return new GuildScheduledEvent(data);
7024
7195
  }
7025
7196
  keyOf(data) {
@@ -7039,9 +7210,9 @@ var GuildScheduledEventManager = class extends CachedManager {
7039
7210
  }
7040
7211
  _hydrate(data) {
7041
7212
  return whenAll([
7042
- data.creator ? this.client.users._resolveData(data.creator) : data.creator_id ? this.client.users._get(data.creator_id) : void 0,
7213
+ data.creator ? this.client.users._resolveData(data.creator) : data.creator_id ? this.client.users.cache.get(data.creator_id) : void 0,
7043
7214
  this.cachedGuild(data.guild_id),
7044
- data.channel_id ? this.client.channels._get(data.channel_id) : void 0
7215
+ data.channel_id ? this.client.channels.cache.get(data.channel_id) : void 0
7045
7216
  ], ([creator, guild, channel]) => new GuildScheduledEvent(data, {
7046
7217
  creator: creator ?? null,
7047
7218
  guild,
@@ -7084,7 +7255,7 @@ var GuildScheduledEventManager = class extends CachedManager {
7084
7255
  */
7085
7256
  async delete(eventId, reason) {
7086
7257
  await this.client.api.guilds.deleteScheduledEvent(this.guildId, eventId, { reason });
7087
- await this.cache?.delete(this.resolveKey(eventId));
7258
+ await this.cache.delete(this.resolveKey(eventId));
7088
7259
  }
7089
7260
  /**
7090
7261
  * Fetches the users who subscribed to an event, and caches them.
@@ -7230,11 +7401,11 @@ var GuildSoundboardSoundManager = class extends CachedManager {
7230
7401
  super(client, "soundboardSounds");
7231
7402
  this.guildId = guildId;
7232
7403
  }
7233
- construct(data) {
7404
+ createStructure(data) {
7234
7405
  return new SoundboardSound(data);
7235
7406
  }
7236
7407
  keyOf(data) {
7237
- return this.resolveKey(data.sound_id);
7408
+ return soundboardSoundKey(data.guild_id ?? this.guildId, data.sound_id);
7238
7409
  }
7239
7410
  resolveKey(soundId) {
7240
7411
  return soundboardSoundKey(this.guildId, soundId);
@@ -7252,7 +7423,7 @@ var GuildSoundboardSoundManager = class extends CachedManager {
7252
7423
  return whenAll([
7253
7424
  data.user ? this.client.users._resolveData(data.user) : null,
7254
7425
  this.cachedGuild(data.guild_id),
7255
- data.emoji_id && data.guild_id ? this.client.guilds.emojis(data.guild_id)._get(data.emoji_id) : void 0
7426
+ data.emoji_id && data.guild_id ? this.client.guilds.emojis(data.guild_id).cache.get(emojiKey(data.guild_id, data.emoji_id)) : void 0
7256
7427
  ], ([user, guild, emoji]) => new SoundboardSound(data, {
7257
7428
  user,
7258
7429
  guild,
@@ -7298,7 +7469,7 @@ var GuildSoundboardSoundManager = class extends CachedManager {
7298
7469
  */
7299
7470
  async delete(soundId, reason) {
7300
7471
  await this.client.api.guilds.deleteSoundboardSound(this.guildId, soundId, { reason });
7301
- await this.cache?.delete(this.resolveKey(soundId));
7472
+ await this.cache.delete(this.resolveKey(soundId));
7302
7473
  }
7303
7474
  async fetchRaw(soundId) {
7304
7475
  const sound = await this.client.api.guilds.getSoundboardSound(this.guildId, soundId);
@@ -7340,7 +7511,7 @@ var StageInstanceManager = class extends CachedManager {
7340
7511
  super(client, "stageInstances");
7341
7512
  this.guildId = guildId;
7342
7513
  }
7343
- construct(data) {
7514
+ createStructure(data) {
7344
7515
  return new StageInstance(data);
7345
7516
  }
7346
7517
  keyOf(data) {
@@ -7352,8 +7523,8 @@ var StageInstanceManager = class extends CachedManager {
7352
7523
  _hydrate(data) {
7353
7524
  return whenAll([
7354
7525
  this.cachedGuild(data.guild_id),
7355
- this.client.channels._get(data.channel_id),
7356
- data.guild_scheduled_event_id ? this.client.guilds.scheduledEvents(data.guild_id)._get(data.guild_scheduled_event_id) : void 0
7526
+ this.client.channels.cache.get(data.channel_id),
7527
+ data.guild_scheduled_event_id ? this.client.guilds.scheduledEvents(data.guild_id).cache.get(scheduledEventKey(data.guild_id, data.guild_scheduled_event_id)) : void 0
7357
7528
  ], ([guild, channel, guildScheduledEvent]) => new StageInstance(data, {
7358
7529
  guild,
7359
7530
  channel: channel ?? null,
@@ -7399,7 +7570,7 @@ var StageInstanceManager = class extends CachedManager {
7399
7570
  */
7400
7571
  async delete(channelId, reason) {
7401
7572
  await this.client.api.stageInstances.delete(channelId, { reason });
7402
- await this.cache?.delete(this.resolveKey(channelId));
7573
+ await this.cache.delete(this.resolveKey(channelId));
7403
7574
  }
7404
7575
  async fetchRaw(channelId) {
7405
7576
  return this.client.api.stageInstances.get(channelId);
@@ -7420,7 +7591,7 @@ var GuildEmojiManager = class extends CachedManager {
7420
7591
  super(client, "emojis");
7421
7592
  this.guildId = guildId;
7422
7593
  }
7423
- construct(data) {
7594
+ createStructure(data) {
7424
7595
  return new GuildEmoji(data);
7425
7596
  }
7426
7597
  keyOf(data) {
@@ -7460,7 +7631,7 @@ var GuildEmojiManager = class extends CachedManager {
7460
7631
  const body = {
7461
7632
  image: await resolveImage(options.attachment),
7462
7633
  name: options.name,
7463
- roles: options.roles ? [...options.roles] : void 0
7634
+ roles: options.roles ? resolveRoleIds(options.roles) : void 0
7464
7635
  };
7465
7636
  const emoji = await this.client.api.guilds.createEmoji(this.guildId, body, { reason: options.reason });
7466
7637
  return this.store(emoji);
@@ -7474,7 +7645,7 @@ var GuildEmojiManager = class extends CachedManager {
7474
7645
  async edit(emojiId, options) {
7475
7646
  const body = {
7476
7647
  name: options.name,
7477
- roles: options.roles === void 0 || options.roles === null ? options.roles : [...options.roles]
7648
+ roles: options.roles === void 0 || options.roles === null ? options.roles : resolveRoleIds(options.roles)
7478
7649
  };
7479
7650
  const emoji = await this.client.api.guilds.editEmoji(this.guildId, emojiId, body, { reason: options.reason });
7480
7651
  return this.store(emoji);
@@ -7487,7 +7658,7 @@ var GuildEmojiManager = class extends CachedManager {
7487
7658
  */
7488
7659
  async delete(emojiId, reason) {
7489
7660
  await this.client.api.guilds.deleteEmoji(this.guildId, emojiId, { reason });
7490
- await this.cache?.delete(this.resolveKey(emojiId));
7661
+ await this.cache.delete(this.resolveKey(emojiId));
7491
7662
  }
7492
7663
  /**
7493
7664
  * Fetches the user who uploaded an emoji, which the API only returns with `ManageGuildExpressions`.
@@ -7511,9 +7682,9 @@ var GuildEmojiManager = class extends CachedManager {
7511
7682
  const cache = this.iterableCache();
7512
7683
  if (!cache) return [];
7513
7684
  const prefix = `${this.guildId}:`;
7514
- const keys = (await cache.keys()).filter((key) => key.startsWith(prefix));
7515
- const values = await Promise.all(keys.map((key) => cache.get(key)));
7516
- return Promise.all(values.filter((value) => value !== void 0).map((value) => this.hydrate(value)));
7685
+ const keys = await this.guard("keys", null, () => cache.keys(), []);
7686
+ const values = await Promise.all(keys.filter((key) => key.startsWith(prefix)).map((key) => this.guard("get", key, () => cache.get(key), void 0)));
7687
+ return Promise.all(values.filter((value) => value !== void 0).map((value) => this._build(value)));
7517
7688
  }
7518
7689
  async fetchRaw(emojiId) {
7519
7690
  return {
@@ -7543,11 +7714,11 @@ var GuildInviteManager = class extends CachedManager {
7543
7714
  super(client, "invites");
7544
7715
  this.guildId = guildId;
7545
7716
  }
7546
- construct(data) {
7717
+ createStructure(data) {
7547
7718
  return new GuildInvite(data);
7548
7719
  }
7549
7720
  keyOf(data) {
7550
- return this.resolveKey(data.code);
7721
+ return inviteKey(data.guild_id ?? this.guildId, resolveInviteCode(data.code));
7551
7722
  }
7552
7723
  /**
7553
7724
  * Adds an invite to the cache, and its inviter and target user to `client.users`.
@@ -7564,8 +7735,8 @@ var GuildInviteManager = class extends CachedManager {
7564
7735
  return whenAll([
7565
7736
  data.inviter ? users._resolveData(data.inviter) : void 0,
7566
7737
  data.target_user ? users._resolveData(data.target_user) : void 0,
7567
- this.cachedGuild(this.guildId),
7568
- data.channel_id ? this.client.channels._get(data.channel_id) : void 0
7738
+ this.cachedGuild(data.guild_id ?? this.guildId),
7739
+ data.channel_id ? this.client.channels.cache.get(data.channel_id) : void 0
7569
7740
  ], ([inviter, targetUser, guild, channel]) => new GuildInvite(data, {
7570
7741
  inviter,
7571
7742
  targetUser,
@@ -7619,7 +7790,7 @@ var GuildInviteManager = class extends CachedManager {
7619
7790
  */
7620
7791
  async delete(code, reason) {
7621
7792
  await this.client.api.invites.delete(resolveInviteCode(code), { reason });
7622
- await this.cache?.delete(this.resolveKey(code));
7793
+ await this.cache.delete(this.resolveKey(code));
7623
7794
  }
7624
7795
  async fetchRaw(code) {
7625
7796
  const invite = await this.client.api.invites.get(resolveInviteCode(code), { with_counts: true });
@@ -7651,7 +7822,7 @@ var GuildStickerManager = class extends CachedManager {
7651
7822
  super(client, "stickers");
7652
7823
  this.guildId = guildId;
7653
7824
  }
7654
- construct(data) {
7825
+ createStructure(data) {
7655
7826
  return new Sticker(data);
7656
7827
  }
7657
7828
  keyOf(data) {
@@ -7719,7 +7890,7 @@ var GuildStickerManager = class extends CachedManager {
7719
7890
  */
7720
7891
  async delete(stickerId, reason) {
7721
7892
  await this.client.api.guilds.deleteSticker(this.guildId, stickerId, { reason });
7722
- await this.cache?.delete(this.resolveKey(stickerId));
7893
+ await this.cache.delete(this.resolveKey(stickerId));
7723
7894
  }
7724
7895
  /**
7725
7896
  * Fetches the user who uploaded a sticker, which the API only returns with `ManageGuildExpressions`.
@@ -7743,9 +7914,9 @@ var GuildStickerManager = class extends CachedManager {
7743
7914
  const cache = this.iterableCache();
7744
7915
  if (!cache) return [];
7745
7916
  const prefix = `${this.guildId}:`;
7746
- const keys = (await cache.keys()).filter((key) => key.startsWith(prefix));
7747
- const values = await Promise.all(keys.map((key) => cache.get(key)));
7748
- return Promise.all(values.filter((value) => value !== void 0).map((value) => this.hydrate(value)));
7917
+ const keys = await this.guard("keys", null, () => cache.keys(), []);
7918
+ const values = await Promise.all(keys.filter((key) => key.startsWith(prefix)).map((key) => this.guard("get", key, () => cache.get(key), void 0)));
7919
+ return Promise.all(values.filter((value) => value !== void 0).map((value) => this._build(value)));
7749
7920
  }
7750
7921
  async fetchRaw(stickerId) {
7751
7922
  return {
@@ -7770,7 +7941,7 @@ var GuildManager = class extends CachedManager {
7770
7941
  constructor(client) {
7771
7942
  super(client, "guilds");
7772
7943
  }
7773
- construct(data) {
7944
+ createStructure(data) {
7774
7945
  return new Guild(data);
7775
7946
  }
7776
7947
  keyOf(data) {
@@ -7802,7 +7973,8 @@ var GuildManager = class extends CachedManager {
7802
7973
  * @internal
7803
7974
  */
7804
7975
  _getShallow(guildId) {
7805
- return whenAll([this.cache?.get(guildId)], ([raw]) => raw === void 0 ? void 0 : bindClient(this.construct(raw), this.client));
7976
+ const read = this.guard("get", guildId, () => this.rawStore?.get(guildId), void 0);
7977
+ return whenAll([read], ([raw]) => raw === void 0 ? void 0 : bindClient(this.createStructure(raw), this.client));
7806
7978
  }
7807
7979
  resolveKey(guildId) {
7808
7980
  return guildId;
@@ -7895,9 +8067,7 @@ var GuildManager = class extends CachedManager {
7895
8067
  channel_id: options.channel === void 0 ? void 0 : options.channel && resolveId(options.channel)
7896
8068
  };
7897
8069
  const settings = await this.client.api.guilds.editWidgetSettings(guildId, body, { reason: options.reason });
7898
- const cached = await this.cache?.get(guildId);
7899
- if (cached) await this.cache.set(guildId, {
7900
- ...cached,
8070
+ await this._patchCached(guildId, {
7901
8071
  widget_enabled: settings.enabled,
7902
8072
  widget_channel_id: settings.channel_id
7903
8073
  });
@@ -7987,9 +8157,9 @@ var GuildManager = class extends CachedManager {
7987
8157
  const integrations = this.integrations(guildId);
7988
8158
  const [webhooks, autoModerationRules, threads, pageIntegrations] = await Promise.all([
7989
8159
  Promise.all(log.webhooks.map((webhook) => this.client.webhooks.hydrate(webhook))),
7990
- Promise.all(log.auto_moderation_rules.map((rule) => rules.hydrate(rule))),
7991
- Promise.all(log.threads.map((thread) => this.client.threads.hydrate(thread))),
7992
- Promise.all(log.integrations.map((integration) => integrations.hydrate({
8160
+ Promise.all(log.auto_moderation_rules.map((rule) => rules._build(rule))),
8161
+ Promise.all(log.threads.map((thread) => this.client.threads._build(thread))),
8162
+ Promise.all(log.integrations.map((integration) => integrations._build({
7993
8163
  ...integration,
7994
8164
  guild_id: guildId
7995
8165
  })))
@@ -8161,11 +8331,7 @@ var GuildManager = class extends CachedManager {
8161
8331
  dms_disabled_until: toISO(options.dmsDisabledUntil)
8162
8332
  };
8163
8333
  const incidents = await this.client.api.guilds.editIncidentActions(guildId, body);
8164
- const cached = await this.cache?.get(guildId);
8165
- if (cached) await this.cache.set(guildId, {
8166
- ...cached,
8167
- incidents_data: incidents
8168
- });
8334
+ await this._patchCached(guildId, { incidents_data: incidents });
8169
8335
  return transformAPIIncidentsData(incidents);
8170
8336
  }
8171
8337
  async fetchRaw(guildId) {
@@ -8176,10 +8342,11 @@ var GuildManager = class extends CachedManager {
8176
8342
  }
8177
8343
  async welcomeScreen(guildId, screen) {
8178
8344
  const channels = screen.welcome_channels;
8179
- const [guild, cachedChannels, emojis] = await Promise.all([
8345
+ const emojis = this.emojis(guildId);
8346
+ const [guild, cachedChannels, cachedEmojis] = await Promise.all([
8180
8347
  this.cachedGuild(guildId),
8181
- cachedMap(channels.map((channel) => channel.channel_id), (id) => this.client.channels.get(id)),
8182
- cachedMap(channels.flatMap((channel) => channel.emoji_id ? [channel.emoji_id] : []), (id) => this.emojis(guildId).get(id))
8348
+ cachedMap(channels.map((channel) => channel.channel_id), (id) => this.client.channels.cache.get(id)),
8349
+ cachedMap(channels.flatMap((channel) => channel.emoji_id ? [channel.emoji_id] : []), (id) => emojis.cache.get(emojis.resolveKey(id)))
8183
8350
  ]);
8184
8351
  return bindClient(new WelcomeScreen({
8185
8352
  ...screen,
@@ -8187,22 +8354,23 @@ var GuildManager = class extends CachedManager {
8187
8354
  }, {
8188
8355
  guild,
8189
8356
  channels: cachedChannels,
8190
- emojis
8357
+ emojis: cachedEmojis
8191
8358
  }), this.client);
8192
8359
  }
8193
8360
  async onboarding(guildId, onboarding) {
8194
8361
  const options = onboarding.prompts.flatMap((prompt) => prompt.options);
8195
- const [guild, channels, roles, emojis] = await Promise.all([
8362
+ const emojis = this.emojis(guildId);
8363
+ const [guild, channels, roles, cachedEmojis] = await Promise.all([
8196
8364
  this.cachedGuild(guildId),
8197
- cachedMap([...onboarding.default_channel_ids, ...options.flatMap((option) => option.channel_ids)], (id) => this.client.channels.get(id)),
8198
- cachedMap(options.flatMap((option) => option.role_ids), (id) => this.client.roles.get(guildId, id)),
8199
- cachedMap(options.flatMap((option) => option.emoji?.id ? [option.emoji.id] : []), (id) => this.emojis(guildId).get(id))
8365
+ cachedMap([...onboarding.default_channel_ids, ...options.flatMap((option) => option.channel_ids)], (id) => this.client.channels.cache.get(id)),
8366
+ cachedMap(options.flatMap((option) => option.role_ids), (id) => this.client.roles.cache.get(this.client.roles.resolveKey(guildId, id))),
8367
+ cachedMap(options.flatMap((option) => option.emoji?.id ? [option.emoji.id] : []), (id) => emojis.cache.get(emojis.resolveKey(id)))
8200
8368
  ]);
8201
8369
  return bindClient(new GuildOnboarding(onboarding, {
8202
8370
  guild,
8203
8371
  channels,
8204
8372
  roles,
8205
- emojis
8373
+ emojis: cachedEmojis
8206
8374
  }), this.client);
8207
8375
  }
8208
8376
  async forget(guildId) {
@@ -8218,7 +8386,13 @@ var GuildManager = class extends CachedManager {
8218
8386
  };
8219
8387
  async function cachedMap(ids, get) {
8220
8388
  const unique = [...new Set(ids)];
8221
- const values = await Promise.all(unique.map((id) => get(id).catch(() => void 0)));
8389
+ const values = await Promise.all(unique.map(async (id) => {
8390
+ try {
8391
+ return await get(id);
8392
+ } catch {
8393
+ return;
8394
+ }
8395
+ }));
8222
8396
  const map = /* @__PURE__ */ new Map();
8223
8397
  for (const [index, value] of values.entries()) if (value) map.set(unique[index], value);
8224
8398
  return map;
@@ -8234,117 +8408,219 @@ function toISO(value) {
8234
8408
 
8235
8409
  //#endregion
8236
8410
  //#region src/managers/GuildMemberRoleManager.ts
8411
+ const pick = {
8412
+ highest: (roles) => roles[0] ?? null,
8413
+ hoist: (roles) => roles.find((role) => role.hoist) ?? null,
8414
+ color: (roles) => roles.find((role) => role.colors.primaryColor !== 0) ?? null,
8415
+ icon: (roles) => roles.find((role) => role.icon ?? role.unicodeEmoji) ?? null,
8416
+ premiumSubscriberRole: (roles) => roles.find((role) => role.tags?.premiumSubscriberRole) ?? null,
8417
+ botRole: (roles, userId) => userId !== null && roles.find((role) => role.tags?.botId === userId) || null
8418
+ };
8419
+ function highestFirst(roles) {
8420
+ return [...roles].toSorted((a, b) => b.comparePositionTo(a));
8421
+ }
8237
8422
  /**
8238
- * Manages the roles of one {@link GuildMember}, reading them through the client's role manager.
8423
+ * Manages the roles of one {@link GuildMember}, like discord.js's `GuildMemberRoleManager`.
8239
8424
  *
8240
8425
  * @remarks
8241
- * discord.js's synchronous `member.roles.cache`, `highest`, `color`, ... become the `fetch*` methods here: the roles
8242
- * are read from the (possibly asynchronous) cache, falling back to the API.
8426
+ * The one deliberate difference from discord.js: {@link GuildMemberRoleManager.cache} and the getters reading it
8427
+ * (`highest`, `hoist`, `color`, ...) are `Awaitable`, like `manager.cache.get`. They are synchronous with the default
8428
+ * in-memory cache and a promise with a remote store, so `await` works with both.
8429
+ *
8430
+ * They only know the roles the cache holds. The `fetch*` methods fall back to the API when a role is not cached.
8243
8431
  */
8244
- var GuildMemberRoleManager = class {
8245
- client;
8246
- guildId;
8247
- userId;
8248
- #roleIds;
8432
+ var GuildMemberRoleManager = class GuildMemberRoleManager extends BaseManager {
8249
8433
  /**
8250
- * @param client The client.
8251
- * @param guildId The ID of the guild.
8252
- * @param userId The ID of the member's user.
8253
- * @param roleIds The IDs of the member's roles, as known to the member structure.
8434
+ * The member these roles belong to.
8254
8435
  */
8255
- constructor(client, guildId, userId, roleIds) {
8256
- this.client = client;
8257
- this.guildId = guildId;
8258
- this.userId = userId;
8259
- this.#roleIds = roleIds;
8436
+ member;
8437
+ /**
8438
+ * @param member The member.
8439
+ */
8440
+ constructor(member) {
8441
+ super(member.client);
8442
+ this.member = member;
8443
+ }
8444
+ /**
8445
+ * The member's guild, from the cache: `null` when it is not cached.
8446
+ */
8447
+ get guild() {
8448
+ return this.member.guild;
8449
+ }
8450
+ get guildId() {
8451
+ return this.member.guildId;
8452
+ }
8453
+ /**
8454
+ * The ID of the member's user.
8455
+ *
8456
+ * @throws {GatewayError} `GuildMemberUserUnknown` when the member's payload did not include its user.
8457
+ */
8458
+ get userId() {
8459
+ const { id } = this.member;
8460
+ if (id === null) throw new GatewayError("GuildMemberUserUnknown");
8461
+ return id;
8260
8462
  }
8261
8463
  /**
8262
8464
  * The IDs of the member's roles, `@everyone` excluded.
8263
8465
  */
8264
8466
  get ids() {
8265
- return this.#roleIds;
8467
+ return this.member.roleIds;
8468
+ }
8469
+ /**
8470
+ * The member's roles held in the cache, by ID, `@everyone` included. Roles that are not cached are skipped: use
8471
+ * {@link GuildMemberRoleManager.fetch} to get them all.
8472
+ */
8473
+ get cache() {
8474
+ return cachedRoles(this.client, this.guildId, [...this.ids, this.guildId]);
8475
+ }
8476
+ /**
8477
+ * The member's highest cached role. `null` when none of their roles is cached, `@everyone` included.
8478
+ */
8479
+ get highest() {
8480
+ return this.fromCache(pick.highest);
8481
+ }
8482
+ /**
8483
+ * The cached role the member is displayed under in the member list, if any.
8484
+ */
8485
+ get hoist() {
8486
+ return this.fromCache(pick.hoist);
8487
+ }
8488
+ /**
8489
+ * The highest cached role giving the member a color, if any.
8490
+ */
8491
+ get color() {
8492
+ return this.fromCache(pick.color);
8493
+ }
8494
+ /**
8495
+ * The highest cached role giving the member an icon, if any.
8496
+ */
8497
+ get icon() {
8498
+ return this.fromCache(pick.icon);
8499
+ }
8500
+ /**
8501
+ * The server booster role, if the member has it and it is cached.
8502
+ */
8503
+ get premiumSubscriberRole() {
8504
+ return this.fromCache(pick.premiumSubscriberRole);
8505
+ }
8506
+ /**
8507
+ * The role Discord manages for the member, when the member is a bot and the role is cached.
8508
+ */
8509
+ get botRole() {
8510
+ return this.fromCache((roles) => pick.botRole(roles, this.member.id));
8266
8511
  }
8267
8512
  /**
8268
8513
  * Fetches the member's roles, `@everyone` included, highest first.
8269
8514
  */
8270
8515
  async fetch() {
8271
- const ids = [...this.#roleIds, this.guildId];
8272
- let roles = (await Promise.all(ids.map((id) => this.client.roles.get(this.guildId, id)))).filter((role) => role !== void 0);
8273
- if (roles.length !== ids.length) {
8516
+ const ids = [...this.ids, this.guildId];
8517
+ let roles = [...(await this.cache).values()];
8518
+ if (roles.length !== new Set(ids).size) {
8274
8519
  const wanted = new Set(ids);
8275
8520
  roles = (await this.client.roles.fetchAll(this.guildId)).filter((role) => wanted.has(role.id));
8276
8521
  }
8277
- return roles.toSorted((a, b) => b.comparePositionTo(a));
8522
+ return highestFirst(roles);
8278
8523
  }
8279
8524
  /**
8280
8525
  * Fetches the member's highest role, `@everyone` when they have no other.
8281
8526
  */
8282
8527
  async fetchHighest() {
8283
- return (await this.fetch())[0] ?? null;
8528
+ return pick.highest(await this.fetch());
8284
8529
  }
8285
8530
  /**
8286
8531
  * Fetches the role the member is displayed under in the member list, if any.
8287
8532
  */
8288
8533
  async fetchHoist() {
8289
- return (await this.fetch()).find((role) => role.hoist) ?? null;
8534
+ return pick.hoist(await this.fetch());
8290
8535
  }
8291
8536
  /**
8292
8537
  * Fetches the highest role giving the member a color, if any.
8293
8538
  */
8294
8539
  async fetchColor() {
8295
- return (await this.fetch()).find((role) => role.color !== 0) ?? null;
8540
+ return pick.color(await this.fetch());
8296
8541
  }
8297
8542
  /**
8298
8543
  * Fetches the highest role giving the member an icon, if any.
8299
8544
  */
8300
8545
  async fetchIcon() {
8301
- return (await this.fetch()).find((role) => role.icon ?? role.unicodeEmoji) ?? null;
8546
+ return pick.icon(await this.fetch());
8302
8547
  }
8303
8548
  /**
8304
8549
  * Fetches the server booster role, if the member has it.
8305
8550
  */
8306
8551
  async fetchPremiumSubscriberRole() {
8307
- return (await this.fetch()).find((role) => role.tags?.premiumSubscriberRole) ?? null;
8552
+ return pick.premiumSubscriberRole(await this.fetch());
8308
8553
  }
8309
8554
  /**
8310
8555
  * Fetches the role Discord manages for the member, when the member is a bot.
8311
8556
  */
8312
8557
  async fetchBotRole() {
8313
- return (await this.fetch()).find((role) => role.tags?.botId === this.userId) ?? null;
8558
+ return pick.botRole(await this.fetch(), this.member.id);
8314
8559
  }
8315
8560
  /**
8316
- * Adds roles to the member.
8561
+ * Adds a role, or several, to the member.
8562
+ *
8563
+ * @remarks
8564
+ * A single role goes through its own endpoint and resolves to a copy of the member with the role added. Several
8565
+ * roles replace the member's roles, like {@link GuildMemberRoleManager.set}.
8317
8566
  *
8318
- * @param roles The ID of the role, or several IDs.
8567
+ * @param roleOrRoles The role or its ID, or an array or `Collection` of them.
8319
8568
  * @param reason The reason for the audit log.
8569
+ * @returns The updated member.
8320
8570
  */
8321
- async add(roles, reason) {
8322
- if (typeof roles === "string") return this.client.members.addRole(this.guildId, this.userId, roles, reason);
8323
- return this.set([.../* @__PURE__ */ new Set([...this.#roleIds, ...roles])], reason);
8571
+ async add(roleOrRoles, reason) {
8572
+ if (isRoleResolvables(roleOrRoles)) return this.set([.../* @__PURE__ */ new Set([...this.ids, ...resolveRoleIds(roleOrRoles)])], reason);
8573
+ const roleId = this.resolveSingle(roleOrRoles);
8574
+ await this.client.members.addRole(this.guildId, this.userId, roleId, reason);
8575
+ return this.member[kClone]({ roles: [.../* @__PURE__ */ new Set([...this.ids, roleId])] });
8324
8576
  }
8325
8577
  /**
8326
- * Removes roles from the member.
8578
+ * Removes a role, or several, from the member.
8579
+ *
8580
+ * @remarks
8581
+ * A single role goes through its own endpoint and resolves to a copy of the member with the role removed. Several
8582
+ * roles replace the member's roles, like {@link GuildMemberRoleManager.set}.
8327
8583
  *
8328
- * @param roles The ID of the role, or several IDs.
8584
+ * @param roleOrRoles The role or its ID, or an array or `Collection` of them.
8329
8585
  * @param reason The reason for the audit log.
8586
+ * @returns The updated member.
8330
8587
  */
8331
- async remove(roles, reason) {
8332
- if (typeof roles === "string") return this.client.members.removeRole(this.guildId, this.userId, roles, reason);
8333
- const removed = new Set(roles);
8334
- return this.set(this.#roleIds.filter((id) => !removed.has(id)), reason);
8588
+ async remove(roleOrRoles, reason) {
8589
+ if (isRoleResolvables(roleOrRoles)) {
8590
+ const removed = new Set(resolveRoleIds(roleOrRoles));
8591
+ return this.set(this.ids.filter((id) => !removed.has(id)), reason);
8592
+ }
8593
+ const roleId = this.resolveSingle(roleOrRoles);
8594
+ await this.client.members.removeRole(this.guildId, this.userId, roleId, reason);
8595
+ return this.member[kClone]({ roles: this.ids.filter((id) => id !== roleId) });
8335
8596
  }
8336
8597
  /**
8337
8598
  * Replaces the member's roles.
8338
8599
  *
8339
- * @param roles The IDs of the roles the member ends up with.
8600
+ * @param roles The roles the member ends up with: an array of roles or IDs, or a `Collection` of roles.
8340
8601
  * @param reason The reason for the audit log.
8602
+ * @returns The member, patched.
8341
8603
  */
8342
8604
  set(roles, reason) {
8343
- return this.client.members.edit(this.guildId, this.userId, {
8605
+ return this.member.edit({
8344
8606
  roles,
8345
8607
  reason
8346
8608
  });
8347
8609
  }
8610
+ /**
8611
+ * Creates another manager of the same member's roles.
8612
+ */
8613
+ clone() {
8614
+ return new GuildMemberRoleManager(this.member);
8615
+ }
8616
+ fromCache(picker) {
8617
+ return whenAll([this.cache], ([cache]) => picker(highestFirst(cache.values())));
8618
+ }
8619
+ resolveSingle(role) {
8620
+ const roleId = resolveRoleId(role);
8621
+ if (roleId === null) throw new GatewayTypeError("InvalidType", "roles", "Role, Snowflake or Array or Collection of Roles or Snowflakes");
8622
+ return roleId;
8623
+ }
8348
8624
  };
8349
8625
 
8350
8626
  //#endregion
@@ -8419,10 +8695,10 @@ var GuildMember = class extends Structure {
8419
8695
  return this[kData].roles;
8420
8696
  }
8421
8697
  /**
8422
- * The member's roles. It needs the member's user ID, which every payload but some partial ones carries.
8698
+ * The member's roles. Changing them needs the member's user ID, which every payload but some partial ones carries.
8423
8699
  */
8424
8700
  get roles() {
8425
- return new GuildMemberRoleManager(this.client, this.guildId, this.requireId(), this.roleIds);
8701
+ return new GuildMemberRoleManager(this);
8426
8702
  }
8427
8703
  get joinedTimestamp() {
8428
8704
  return this.optimizedTimestamp("joined_at");
@@ -8599,13 +8875,13 @@ var GuildMember = class extends Structure {
8599
8875
  * @returns The presence, or `null` when it is not cached (the bot needs the `GuildPresences` intent).
8600
8876
  */
8601
8877
  async fetchPresence() {
8602
- return await this.client.presences.get(this.guildId, this.requireId()) ?? null;
8878
+ return await this.client.presences.cache.get(this.client.presences.resolveKey(this.guildId, this.requireId())) ?? null;
8603
8879
  }
8604
8880
  /**
8605
8881
  * Fetches the color the member's name is displayed in, `0` when none of their roles has one.
8606
8882
  */
8607
8883
  async fetchDisplayColor() {
8608
- return (await this.roles.fetchColor())?.color ?? 0;
8884
+ return (await this.roles.fetchColor())?.colors.primaryColor ?? 0;
8609
8885
  }
8610
8886
  /**
8611
8887
  * Fetches the color the member's name is displayed in, as a `#rrggbb` string.
@@ -8692,8 +8968,13 @@ var GuildMember = class extends Structure {
8692
8968
  await this.client.members.ban(this.guildId, this.requireId(), options);
8693
8969
  return this;
8694
8970
  }
8695
- createDM() {
8696
- return this.client.users.createDM(this.requireId());
8971
+ /**
8972
+ * Opens a direct message channel with the member, reusing the cached one.
8973
+ *
8974
+ * @param force Whether to skip the cache lookup and always call the API.
8975
+ */
8976
+ createDM(force = false) {
8977
+ return this.client.users.createDM(this.requireId(), { force });
8697
8978
  }
8698
8979
  deleteDM() {
8699
8980
  return this.client.users.deleteDM(this.requireId());
@@ -9303,7 +9584,7 @@ var GuildMemberManager = class extends CachedManager {
9303
9584
  constructor(client) {
9304
9585
  super(client, "members");
9305
9586
  }
9306
- construct(data) {
9587
+ createStructure(data) {
9307
9588
  return new GuildMember(data);
9308
9589
  }
9309
9590
  keyOf(data) {
@@ -9334,15 +9615,15 @@ var GuildMemberManager = class extends CachedManager {
9334
9615
  return whenAll([
9335
9616
  data.user ? client.users._resolveData(data.user) : void 0,
9336
9617
  this.cachedGuild(data.guild_id),
9337
- key ? client.cache?.voiceStates?.get(key) : void 0,
9338
- key ? client.cache?.presences?.get(key) : void 0
9618
+ key ? this.readRelation("voiceStates", key) : void 0,
9619
+ key ? this.readRelation("presences", key) : void 0
9339
9620
  ], ([user, guild, voiceData, presenceData]) => {
9340
9621
  const relations = {
9341
9622
  user,
9342
9623
  guild
9343
9624
  };
9344
9625
  const member = bindClient(new GuildMember(data, relations), client);
9345
- return whenAll([voiceData?.channel_id ? client.channels._get(voiceData.channel_id) : void 0], ([channel]) => {
9626
+ return whenAll([voiceData?.channel_id ? client.channels.cache.get(voiceData.channel_id) : void 0], ([channel]) => {
9346
9627
  if (key && client.cache?.voiceStates) relations.voice = voiceData ? bindClient(new VoiceState(voiceData, {
9347
9628
  member,
9348
9629
  guild,
@@ -9357,6 +9638,10 @@ var GuildMemberManager = class extends CachedManager {
9357
9638
  });
9358
9639
  });
9359
9640
  }
9641
+ readRelation(name, key) {
9642
+ const store = this.client.cache?.[name];
9643
+ return this.client.guardCache(name, "get", key, () => store?.get(key), void 0);
9644
+ }
9360
9645
  resolveKey(guildId, userId) {
9361
9646
  return memberKey(guildId, userId);
9362
9647
  }
@@ -9497,7 +9782,7 @@ var GuildMemberManager = class extends CachedManager {
9497
9782
  const body = {
9498
9783
  access_token: options.accessToken,
9499
9784
  nick: options.nick,
9500
- roles: options.roles ? [...options.roles] : void 0,
9785
+ roles: options.roles ? resolveRoleIds(options.roles) : void 0,
9501
9786
  mute: options.mute,
9502
9787
  deaf: options.deaf
9503
9788
  };
@@ -9515,7 +9800,7 @@ var GuildMemberManager = class extends CachedManager {
9515
9800
  const until = options.communicationDisabledUntil;
9516
9801
  const body = {
9517
9802
  nick: options.nick,
9518
- roles: options.roles ? [...options.roles] : void 0,
9803
+ roles: options.roles ? resolveRoleIds(options.roles) : void 0,
9519
9804
  mute: options.mute,
9520
9805
  deaf: options.deaf,
9521
9806
  channel_id: options.channel,
@@ -9550,7 +9835,7 @@ var GuildMemberManager = class extends CachedManager {
9550
9835
  */
9551
9836
  async kick(guildId, userId, reason) {
9552
9837
  await this.client.api.guilds.removeMember(guildId, userId, { reason });
9553
- await this.cache?.delete(this.resolveKey(guildId, userId));
9838
+ await this.cache.delete(this.resolveKey(guildId, userId));
9554
9839
  }
9555
9840
  /**
9556
9841
  * Bans a user, member or not.
@@ -9562,7 +9847,7 @@ var GuildMemberManager = class extends CachedManager {
9562
9847
  async ban(guildId, userId, options = {}) {
9563
9848
  const body = { delete_message_seconds: options.deleteMessageSeconds };
9564
9849
  await this.client.api.guilds.banUser(guildId, userId, body, { reason: options.reason });
9565
- await this.cache?.delete(this.resolveKey(guildId, userId));
9850
+ await this.cache.delete(this.resolveKey(guildId, userId));
9566
9851
  }
9567
9852
  /**
9568
9853
  * Lifts a user's ban.
@@ -9588,7 +9873,7 @@ var GuildMemberManager = class extends CachedManager {
9588
9873
  delete_message_seconds: options.deleteMessageSeconds
9589
9874
  };
9590
9875
  const result = await this.client.api.guilds.bulkBanUsers(guildId, body, { reason: options.reason });
9591
- await Promise.all(result.banned_users.map((userId) => this.cache?.delete(this.resolveKey(guildId, userId))));
9876
+ await Promise.all(result.banned_users.map((userId) => this.cache.delete(this.resolveKey(guildId, userId))));
9592
9877
  return {
9593
9878
  bannedUsers: result.banned_users,
9594
9879
  failedUsers: result.failed_users
@@ -9643,24 +9928,19 @@ var GuildMemberManager = class extends CachedManager {
9643
9928
  guild_id: guildId
9644
9929
  };
9645
9930
  }
9646
- store(guildId, member) {
9931
+ async store(guildId, member) {
9647
9932
  const raw = {
9648
9933
  ...member,
9649
9934
  guild_id: guildId
9650
9935
  };
9651
- return raw.user ? this._add(raw) : this.hydrate(raw);
9936
+ return raw.user ? this._add(raw) : this._build(raw);
9652
9937
  }
9653
9938
  settle(nonce, request) {
9654
9939
  if (request.timer) clearTimeout(request.timer);
9655
9940
  this.#requests.delete(nonce);
9656
9941
  }
9657
9942
  async updateCachedRoles(guildId, userId, update) {
9658
- const key = this.resolveKey(guildId, userId);
9659
- const cached = await this.cache?.get(key);
9660
- if (cached) await this.cache.set(key, {
9661
- ...cached,
9662
- roles: update(cached.roles)
9663
- });
9943
+ await this._patchCached(this.resolveKey(guildId, userId), (cached) => ({ roles: update(cached.roleIds) }));
9664
9944
  }
9665
9945
  };
9666
9946
 
@@ -9669,8 +9949,7 @@ var GuildMemberManager = class extends CachedManager {
9669
9949
  /**
9670
9950
  * Manages the users who reacted to a message with one emoji.
9671
9951
  */
9672
- var ReactionUserManager = class {
9673
- client;
9952
+ var ReactionUserManager = class extends BaseManager {
9674
9953
  channelId;
9675
9954
  messageId;
9676
9955
  /**
@@ -9678,7 +9957,7 @@ var ReactionUserManager = class {
9678
9957
  */
9679
9958
  emoji;
9680
9959
  constructor(client, channelId, messageId, emoji) {
9681
- this.client = client;
9960
+ super(client);
9682
9961
  this.channelId = channelId;
9683
9962
  this.messageId = messageId;
9684
9963
  this.emoji = emoji;
@@ -9842,8 +10121,7 @@ Mixin(MessageReaction, [StructureMixin]);
9842
10121
  /**
9843
10122
  * Manages the reactions of one message, as they were in the message's payload.
9844
10123
  */
9845
- var ReactionManager = class {
9846
- client;
10124
+ var ReactionManager = class extends BaseManager {
9847
10125
  channelId;
9848
10126
  messageId;
9849
10127
  #reactions;
@@ -9858,7 +10136,7 @@ var ReactionManager = class {
9858
10136
  * @param emojis The cached custom emojis of the reactions, by ID.
9859
10137
  */
9860
10138
  constructor(client, channelId, messageId, reactions, message = null, emojis) {
9861
- this.client = client;
10139
+ super(client);
9862
10140
  this.channelId = channelId;
9863
10141
  this.messageId = messageId;
9864
10142
  this.#reactions = reactions;
@@ -11383,7 +11661,7 @@ var Message = class Message extends Message$1 {
11383
11661
  const resolved = this[kRelations].thread;
11384
11662
  if (resolved) return resolved;
11385
11663
  const { thread } = this[kData];
11386
- return thread ? this.client.threads.construct(thread) : null;
11664
+ return thread ? this.client.threads.cache.construct(thread) : null;
11387
11665
  }
11388
11666
  /**
11389
11667
  * The content with user, role, and channel mentions replaced by names, and `@everyone`/`@here` defused, like
@@ -11621,7 +11899,7 @@ var MessageManager = class extends CachedManager {
11621
11899
  constructor(client) {
11622
11900
  super(client, "messages");
11623
11901
  }
11624
- construct(data) {
11902
+ createStructure(data) {
11625
11903
  return new Message(data);
11626
11904
  }
11627
11905
  keyOf(data) {
@@ -11646,15 +11924,15 @@ var MessageManager = class extends CachedManager {
11646
11924
  _hydrate(data) {
11647
11925
  const { author, member, guild_id: guildId } = data;
11648
11926
  return whenAll([
11649
- data.webhook_id ? this.client.users.construct(author) : this.client.users._resolveData(author),
11927
+ data.webhook_id ? this.client.users.cache.construct(author) : this.client.users._resolveData(author),
11650
11928
  member && guildId ? this.client.members._resolveData({
11651
11929
  ...member,
11652
11930
  user: author,
11653
11931
  guild_id: guildId
11654
11932
  }) : null,
11655
11933
  this.cachedGuild(guildId),
11656
- this.client.channels._get(data.channel_id),
11657
- data.thread !== void 0 || ((data.flags ?? 0) & MessageFlags.HasThread) !== 0 ? this.client.threads._get(data.id) : void 0,
11934
+ this.client.channels.cache.get(data.channel_id),
11935
+ data.thread !== void 0 || ((data.flags ?? 0) & MessageFlags.HasThread) !== 0 ? this.client.threads.cache.get(data.id) : void 0,
11658
11936
  this.resolveMentions(data),
11659
11937
  guildId ? this.resolveEmojis(guildId, data) : void 0
11660
11938
  ], ([resolvedAuthor, resolvedMember, guild, channel, thread, mentions, emojis]) => new Message(data, {
@@ -11688,7 +11966,7 @@ var MessageManager = class extends CachedManager {
11688
11966
  resolveEmojis(guildId, data) {
11689
11967
  const ids = [...(data.reactions ?? []).map((reaction) => reaction.emoji.id), ...(data.poll?.answers ?? []).map((answer) => answer.poll_media.emoji?.id)].filter((id) => Boolean(id));
11690
11968
  const emojis = this.client.guilds.emojis(guildId);
11691
- return whenCachedMap(ids, (id) => emojis._get(id));
11969
+ return whenCachedMap(ids, (id) => emojis.cache.get(emojis.resolveKey(id)));
11692
11970
  }
11693
11971
  resolveKey(channelId, messageId) {
11694
11972
  return messageKey(channelId, messageId);
@@ -11759,7 +12037,7 @@ var MessageManager = class extends CachedManager {
11759
12037
  */
11760
12038
  async delete(channelId, messageId, reason) {
11761
12039
  await this.client.api.channels.deleteMessage(channelId, messageId, { reason });
11762
- await this.cache?.delete(this.resolveKey(channelId, messageId));
12040
+ await this.cache.delete(this.resolveKey(channelId, messageId));
11763
12041
  }
11764
12042
  /**
11765
12043
  * Deletes up to 100 messages at once, skipping the ones older than 14 days that Discord refuses.
@@ -11779,7 +12057,7 @@ var MessageManager = class extends CachedManager {
11779
12057
  if (ids.length === 1) await this.delete(channelId, ids[0]);
11780
12058
  else {
11781
12059
  await this.client.api.channels.bulkDeleteMessages(channelId, ids);
11782
- await Promise.all(ids.map((id) => this.cache?.delete(this.resolveKey(channelId, id))));
12060
+ await Promise.all(ids.map((id) => this.cache.delete(this.resolveKey(channelId, id))));
11783
12061
  }
11784
12062
  return ids;
11785
12063
  }
@@ -11811,7 +12089,7 @@ var MessageManager = class extends CachedManager {
11811
12089
  */
11812
12090
  async pin(channelId, messageId, reason) {
11813
12091
  await this.client.api.channels.pinMessage(channelId, messageId, { reason });
11814
- await this.patchCached(channelId, messageId, { pinned: true });
12092
+ await this._patchCached(this.resolveKey(channelId, messageId), { pinned: true });
11815
12093
  }
11816
12094
  /**
11817
12095
  * Unpins a message.
@@ -11822,7 +12100,7 @@ var MessageManager = class extends CachedManager {
11822
12100
  */
11823
12101
  async unpin(channelId, messageId, reason) {
11824
12102
  await this.client.api.channels.unpinMessage(channelId, messageId, { reason });
11825
- await this.patchCached(channelId, messageId, { pinned: false });
12103
+ await this._patchCached(this.resolveKey(channelId, messageId), { pinned: false });
11826
12104
  }
11827
12105
  /**
11828
12106
  * Publishes a message of an announcement channel to the channels following it.
@@ -11862,7 +12140,7 @@ var MessageManager = class extends CachedManager {
11862
12140
  */
11863
12141
  async removeAllReactions(channelId, messageId) {
11864
12142
  await this.client.api.channels.deleteAllMessageReactions(channelId, messageId);
11865
- await this.patchCached(channelId, messageId, { reactions: [] });
12143
+ await this._patchCached(this.resolveKey(channelId, messageId), { reactions: [] });
11866
12144
  }
11867
12145
  /**
11868
12146
  * Starts a thread from a message.
@@ -11908,14 +12186,6 @@ var MessageManager = class extends CachedManager {
11908
12186
  store(message) {
11909
12187
  return this._add(message);
11910
12188
  }
11911
- async patchCached(channelId, messageId, patch) {
11912
- const key = this.resolveKey(channelId, messageId);
11913
- const cached = await this.cache?.get(key);
11914
- if (cached) await this.cache.set(key, {
11915
- ...cached,
11916
- ...patch
11917
- });
11918
- }
11919
12189
  };
11920
12190
 
11921
12191
  //#endregion
@@ -12150,7 +12420,7 @@ var RoleManager = class extends CachedManager {
12150
12420
  constructor(client) {
12151
12421
  super(client, "roles");
12152
12422
  }
12153
- construct(data) {
12423
+ createStructure(data) {
12154
12424
  return new Role(data);
12155
12425
  }
12156
12426
  keyOf(data) {
@@ -12213,7 +12483,7 @@ var RoleManager = class extends CachedManager {
12213
12483
  */
12214
12484
  async delete(guildId, roleId, reason) {
12215
12485
  await this.client.api.guilds.deleteRole(guildId, roleId, { reason });
12216
- await this.cache?.delete(this.resolveKey(guildId, roleId));
12486
+ await this.cache.delete(this.resolveKey(guildId, roleId));
12217
12487
  }
12218
12488
  /**
12219
12489
  * Moves a role among the roles of its guild, like discord.js's `RoleManager#setPosition`.
@@ -12333,10 +12603,9 @@ async function toRoleBody(options) {
12333
12603
  * Methods taking a webhook's token call the API with it rather than with the bot's authorization, so they work for
12334
12604
  * webhooks of other applications too.
12335
12605
  */
12336
- var WebhookManager = class {
12337
- client;
12606
+ var WebhookManager = class extends BaseManager {
12338
12607
  constructor(client) {
12339
- this.client = client;
12608
+ super(client);
12340
12609
  }
12341
12610
  /**
12342
12611
  * Fetches a webhook.
@@ -12480,11 +12749,11 @@ var WebhookManager = class {
12480
12749
  */
12481
12750
  async hydrate(data) {
12482
12751
  const [guild, channel, sourceGuild, sourceChannel, owner] = await Promise.all([
12483
- data.guild_id ? this.client.guilds.get(data.guild_id) : void 0,
12484
- data.channel_id ? this.client.channels.get(data.channel_id) : void 0,
12485
- data.source_guild ? this.client.guilds.get(data.source_guild.id) : void 0,
12486
- data.source_channel ? this.client.channels.get(data.source_channel.id) : void 0,
12487
- data.user ? this.client.users.resolveData(data.user) : void 0
12752
+ data.guild_id ? this.client.guilds.cache.get(data.guild_id) : void 0,
12753
+ data.channel_id ? this.client.channels.cache.get(data.channel_id) : void 0,
12754
+ data.source_guild ? this.client.guilds.cache.get(data.source_guild.id) : void 0,
12755
+ data.source_channel ? this.client.channels.cache.get(data.source_channel.id) : void 0,
12756
+ data.user ? this.client.users._resolveData(data.user) : void 0
12488
12757
  ]);
12489
12758
  return bindClient(new Webhook(data, {
12490
12759
  guild: guild ?? null,
@@ -12622,10 +12891,9 @@ var GuildTemplate = class extends Structure {
12622
12891
  /**
12623
12892
  * Manages guild templates. Discord does not send them over the gateway, so they are never cached.
12624
12893
  */
12625
- var GuildTemplateManager = class {
12626
- client;
12894
+ var GuildTemplateManager = class extends BaseManager {
12627
12895
  constructor(client) {
12628
- this.client = client;
12896
+ super(client);
12629
12897
  }
12630
12898
  /**
12631
12899
  * Fetches a template by its code.
@@ -12708,7 +12976,7 @@ var GuildTemplateManager = class {
12708
12976
  }
12709
12977
  async build(template) {
12710
12978
  const creator = await this.client.users._add(template.creator);
12711
- const guild = await this.client.guilds.get(template.source_guild_id) ?? null;
12979
+ const guild = await this.client.guilds.cache.get(template.source_guild_id) ?? null;
12712
12980
  return new GuildTemplate(template, {
12713
12981
  guild,
12714
12982
  creator
@@ -12729,7 +12997,7 @@ var VoiceStateManager = class extends CachedManager {
12729
12997
  constructor(client) {
12730
12998
  super(client, "voiceStates");
12731
12999
  }
12732
- construct(data) {
13000
+ createStructure(data) {
12733
13001
  return new VoiceState(data);
12734
13002
  }
12735
13003
  keyOf(data) {
@@ -12745,9 +13013,9 @@ var VoiceStateManager = class extends CachedManager {
12745
13013
  member?.user && guildId ? this.client.members._resolveData({
12746
13014
  ...member,
12747
13015
  guild_id: guildId
12748
- }) : guildId ? this.client.members._get(guildId, userId) : null,
13016
+ }) : guildId ? this.client.members.cache.get(this.client.members.resolveKey(guildId, userId)) : null,
12749
13017
  this.cachedGuild(guildId),
12750
- data.channel_id ? this.client.channels._get(data.channel_id) : void 0
13018
+ data.channel_id ? this.client.channels.cache.get(data.channel_id) : void 0
12751
13019
  ], ([resolvedMember, guild, channel]) => new VoiceState(data, {
12752
13020
  member: resolvedMember ?? null,
12753
13021
  guild,
@@ -12763,8 +13031,9 @@ var VoiceStateManager = class extends CachedManager {
12763
13031
  */
12764
13032
  async listCached(guildId) {
12765
13033
  const prefix = `${guildId}:`;
12766
- const entries = await this.iterableCache()?.entries() ?? [];
12767
- return Promise.all(entries.filter(([key]) => key.startsWith(prefix)).map(([, raw]) => this.hydrate(raw)));
13034
+ const cache = this.iterableCache();
13035
+ const entries = cache ? await this.guard("entries", null, () => cache.entries(), []) : [];
13036
+ return Promise.all(entries.filter(([key]) => key.startsWith(prefix)).map(([, raw]) => this._build(raw)));
12768
13037
  }
12769
13038
  async fetchRaw(guildId, userId) {
12770
13039
  const client = this.client;
@@ -12783,13 +13052,13 @@ var VoiceStateManager = class extends CachedManager {
12783
13052
  *
12784
13053
  * @remarks
12785
13054
  * Presences only come from the gateway, with the `GuildPresences` intent: there is no API to fetch them, so `fetch`
12786
- * rejects on a cache miss. Use `get`, which resolves to `undefined` instead.
13055
+ * rejects on a cache miss. Use `cache.get`, which answers `undefined` instead.
12787
13056
  */
12788
13057
  var PresenceManager = class extends CachedManager {
12789
13058
  constructor(client) {
12790
13059
  super(client, "presences");
12791
13060
  }
12792
- construct(data) {
13061
+ createStructure(data) {
12793
13062
  return new Presence(data);
12794
13063
  }
12795
13064
  keyOf(data) {
@@ -12800,8 +13069,8 @@ var PresenceManager = class extends CachedManager {
12800
13069
  }
12801
13070
  _hydrate(data) {
12802
13071
  return whenAll([
12803
- this.client.users._get(data.user.id),
12804
- this.client.members._get(data.guild_id, data.user.id),
13072
+ this.client.users.cache.get(data.user.id),
13073
+ this.client.members.cache.get(this.client.members.resolveKey(data.guild_id, data.user.id)),
12805
13074
  this.cachedGuild(data.guild_id)
12806
13075
  ], ([user, member, guild]) => new Presence(data, {
12807
13076
  user: user ?? null,
@@ -12818,8 +13087,9 @@ var PresenceManager = class extends CachedManager {
12818
13087
  */
12819
13088
  async listCached(guildId) {
12820
13089
  const prefix = `${guildId}:`;
12821
- const entries = await this.iterableCache()?.entries() ?? [];
12822
- return Promise.all(entries.filter(([key]) => key.startsWith(prefix)).map(([, raw]) => this.hydrate(raw)));
13090
+ const cache = this.iterableCache();
13091
+ const entries = cache ? await this.guard("entries", null, () => cache.entries(), []) : [];
13092
+ return Promise.all(entries.filter(([key]) => key.startsWith(prefix)).map(([, raw]) => this._build(raw)));
12823
13093
  }
12824
13094
  fetchRaw(guildId, userId) {
12825
13095
  return Promise.reject(new GatewayError("PresenceNotFetchable", guildId, userId));
@@ -12835,7 +13105,7 @@ var ThreadManager = class extends CachedManager {
12835
13105
  constructor(client) {
12836
13106
  super(client, "threads");
12837
13107
  }
12838
- construct(data) {
13108
+ createStructure(data) {
12839
13109
  return createChannel(data);
12840
13110
  }
12841
13111
  keyOf(data) {
@@ -13026,7 +13296,7 @@ var ThreadMemberManager = class extends CachedManager {
13026
13296
  constructor(client) {
13027
13297
  super(client, "threadMembers");
13028
13298
  }
13029
- construct(data) {
13299
+ createStructure(data) {
13030
13300
  return new ThreadMember(data);
13031
13301
  }
13032
13302
  keyOf(data) {
@@ -13055,9 +13325,9 @@ var ThreadMemberManager = class extends CachedManager {
13055
13325
  member?.user && guildId ? this.client.members._resolveData({
13056
13326
  ...member,
13057
13327
  guild_id: guildId
13058
- }) : guildId && userId ? this.client.members._get(guildId, userId) : null,
13059
- data.id ? this.client.threads._get(data.id) : void 0,
13060
- userId ? this.client.users._get(userId) : void 0
13328
+ }) : guildId && userId ? this.client.members.cache.get(this.client.members.resolveKey(guildId, userId)) : null,
13329
+ data.id ? this.client.threads.cache.get(data.id) : void 0,
13330
+ userId ? this.client.users.cache.get(userId) : void 0
13061
13331
  ], ([guildMember, thread, user]) => new ThreadMember(data, {
13062
13332
  guildMember: guildMember ?? null,
13063
13333
  thread: thread ?? null,
@@ -13113,7 +13383,7 @@ var ThreadMemberManager = class extends CachedManager {
13113
13383
  if (userId === "@me") await this.client.api.threads.leave(threadId);
13114
13384
  else await this.client.api.threads.removeMember(threadId, userId);
13115
13385
  const cachedId = userId === "@me" ? this.client.user?.id ?? this.client.id : userId;
13116
- await this.cache?.delete(this.resolveKey(threadId, cachedId));
13386
+ await this.cache.delete(this.resolveKey(threadId, cachedId));
13117
13387
  }
13118
13388
  async fetchRaw(threadId, userId) {
13119
13389
  const member = await this.client.api.threads.getMember(threadId, userId);
@@ -13127,7 +13397,7 @@ var ThreadMemberManager = class extends CachedManager {
13127
13397
  } : member;
13128
13398
  }
13129
13399
  async guildIdOf(threadId) {
13130
- return ((await this.client.threads.get(threadId))?.toJSON())?.guild_id;
13400
+ return ((await this.client.threads.cache.get(threadId))?.toJSON())?.guild_id;
13131
13401
  }
13132
13402
  };
13133
13403
 
@@ -13140,7 +13410,7 @@ var UserManager = class extends CachedManager {
13140
13410
  constructor(client) {
13141
13411
  super(client, "users");
13142
13412
  }
13143
- construct(data) {
13413
+ createStructure(data) {
13144
13414
  return new User(data);
13145
13415
  }
13146
13416
  keyOf(data) {
@@ -13150,43 +13420,102 @@ var UserManager = class extends CachedManager {
13150
13420
  return userId;
13151
13421
  }
13152
13422
  /**
13153
- * Opens a direct message channel with a user, or gets the existing one, and caches it.
13423
+ * Resolves a {@link UserResolvable} to a user: the user of a member or a thread member, the author of a message, or
13424
+ * the cached user of an ID.
13425
+ *
13426
+ * @param user The user, something holding one, or an ID.
13427
+ * @returns The user, or `null` if it is not known.
13428
+ */
13429
+ resolve(user) {
13430
+ if (typeof user === "string" || user instanceof User) return super.resolve(user);
13431
+ if (user instanceof Message) return user.author;
13432
+ return user.user;
13433
+ }
13434
+ /**
13435
+ * Resolves a {@link UserResolvable} to a user ID.
13436
+ *
13437
+ * @param user The user, something holding one, or an ID.
13438
+ * @returns The ID, or `null` if the value holds none.
13439
+ */
13440
+ resolveId(user) {
13441
+ return super.resolveId(user instanceof Message ? user.author : user);
13442
+ }
13443
+ /**
13444
+ * Gets a user from the cache, fetching it from the API (and caching it) on a cache miss.
13445
+ *
13446
+ * @param user The user, something holding one, or an ID.
13447
+ * @param options Whether to skip the cache, and whether to store the result.
13448
+ */
13449
+ fetch(user, options = {}) {
13450
+ return super.fetch(this.requireId(user), options);
13451
+ }
13452
+ /**
13453
+ * Gets the cached direct message channel with a user.
13154
13454
  *
13155
13455
  * @remarks
13156
- * Discord returns the existing channel when there is one, so this always calls the API: unlike discord.js, there is
13157
- * no synchronous `dmChannel` lookup to try first.
13456
+ * It searches the channel cache, which only a synchronous cache that can enumerate its entries allows: the default
13457
+ * `CollectionCache` and the in-memory stores. Other caches (a Redis store, `cache: null`) answer `null`.
13158
13458
  *
13159
- * @param userId The ID of the user.
13459
+ * @param user The user, something holding one, or an ID.
13460
+ * @returns The channel, or `null` when there is none or the cache cannot be searched.
13160
13461
  */
13161
- async createDM(userId) {
13462
+ dmChannel(user) {
13463
+ return whenAll([this.client.channels._findDM(this.requireId(user))], ([channel]) => channel ?? null);
13464
+ }
13465
+ /**
13466
+ * Opens a direct message channel with a user, and caches it. The cached channel is returned without calling the
13467
+ * API, unless `force` is set.
13468
+ *
13469
+ * @param user The user, something holding one, or an ID.
13470
+ * @param options Whether to skip the cache, and whether to store the result.
13471
+ */
13472
+ async createDM(user, { cache = true, force = false } = {}) {
13473
+ const userId = this.requireId(user);
13474
+ if (!force) {
13475
+ const cached = await this.client.channels._findDM(userId);
13476
+ if (cached && !cached.partial) return cached;
13477
+ }
13162
13478
  const channel = await this.client.api.users.createDM(userId);
13163
- return await this.client.channels._add(channel);
13479
+ return await this.client.channels._add(channel, cache);
13164
13480
  }
13165
13481
  /**
13166
13482
  * Closes the direct message channel with a user.
13167
13483
  *
13168
- * @param userId The ID of the user.
13484
+ * @remarks
13485
+ * When the channel cache cannot be searched (see {@link UserManager.dmChannel}), whether a channel exists is
13486
+ * unknown: Discord is asked for it first, and nothing is thrown.
13487
+ *
13488
+ * @param user The user, something holding one, or an ID.
13169
13489
  * @returns The closed channel.
13490
+ * @throws {GatewayError} `UserNoDMChannel` when the cache was searched and holds no channel with the user.
13170
13491
  */
13171
- async deleteDM(userId) {
13172
- const channel = await this.createDM(userId);
13492
+ async deleteDM(user) {
13493
+ const userId = this.requireId(user);
13494
+ const cached = await this.client.channels._findDM(userId);
13495
+ if (cached === null) throw new GatewayError("UserNoDMChannel");
13496
+ const channel = cached ?? await this.createDM(userId, { force: true });
13173
13497
  await this.client.api.channels.delete(channel.id);
13174
- await this.client.cache?.channels?.delete(channel.id);
13498
+ await this.client.channels.cache.delete(channel.id);
13175
13499
  return channel;
13176
13500
  }
13177
13501
  /**
13178
13502
  * Sends a direct message to a user.
13179
13503
  *
13180
- * @param userId The ID of the user.
13504
+ * @param user The user, something holding one, or an ID.
13181
13505
  * @param options The message, or its content.
13182
13506
  */
13183
- async send(userId, options) {
13184
- const channel = await this.createDM(userId);
13507
+ async send(user, options) {
13508
+ const channel = await this.createDM(user);
13185
13509
  return this.client.messages.send(channel.id, options);
13186
13510
  }
13187
13511
  async fetchRaw(userId) {
13188
13512
  return this.client.api.users.get(userId);
13189
13513
  }
13514
+ requireId(user) {
13515
+ const id = this.resolveId(user);
13516
+ if (id === null) throw new GatewayTypeError("IdUnresolvable");
13517
+ return id;
13518
+ }
13190
13519
  };
13191
13520
 
13192
13521
  //#endregion
@@ -13747,6 +14076,15 @@ const Partials = {
13747
14076
 
13748
14077
  //#endregion
13749
14078
  //#region src/util/dispatch.ts
14079
+ async function previousOf(manager, ...args) {
14080
+ const key = manager.resolveKey(...args);
14081
+ const held = await peekCache(manager.cache, key);
14082
+ if (held === void 0) return void 0;
14083
+ return (Object.keys(held[kRelations]).length === 0 ? await manager.cache.get(key) : held)?.[kClone]();
14084
+ }
14085
+ function cachedOf(manager, ...args) {
14086
+ return manager.cache.get(manager.resolveKey(...args));
14087
+ }
13750
14088
  /**
13751
14089
  * The table mapping every supported dispatch to its event.
13752
14090
  *
@@ -13765,30 +14103,30 @@ const DispatchHandlers = {
13765
14103
  },
13766
14104
  [GatewayDispatchEvents.GuildCreate]: {
13767
14105
  event: "guildCreate",
13768
- build: async (client, data) => [await cachedOrUndefined(client.guilds.get(data.id)) ?? await client.guilds.hydrate(data)]
14106
+ build: async (client, data) => [await cachedOrUndefined(() => client.guilds.cache.get(data.id)) ?? await client.guilds._build(data)]
13769
14107
  },
13770
14108
  [GatewayDispatchEvents.GuildUpdate]: {
13771
14109
  event: "guildUpdate",
13772
- before: (client, data) => client.guilds.get(data.id),
13773
- build: async (client, data, previous) => [previous ?? null, await client.guilds.hydrate(data)]
14110
+ before: (client, data) => previousOf(client.guilds, data.id),
14111
+ build: async (client, data, previous) => [previous ?? null, await client.guilds._build(data)]
13774
14112
  },
13775
14113
  [GatewayDispatchEvents.GuildDelete]: {
13776
14114
  event: "guildDelete",
13777
- before: (client, data) => client.guilds.get(data.id),
14115
+ before: (client, data) => previousOf(client.guilds, data.id),
13778
14116
  build: (_client, data, previous) => [previous ?? null, data]
13779
14117
  },
13780
14118
  [GatewayDispatchEvents.ChannelCreate]: {
13781
14119
  event: "channelCreate",
13782
- build: async (client, data) => [await client.channels.hydrate(data)]
14120
+ build: async (client, data) => [await client.channels._build(data)]
13783
14121
  },
13784
14122
  [GatewayDispatchEvents.ChannelUpdate]: {
13785
14123
  event: "channelUpdate",
13786
- before: (client, data) => client.channels.get(data.id),
13787
- build: async (client, data, previous) => [previous ?? null, await client.channels.hydrate(data)]
14124
+ before: (client, data) => previousOf(client.channels, data.id),
14125
+ build: async (client, data, previous) => [previous ?? null, await client.channels._build(data)]
13788
14126
  },
13789
14127
  [GatewayDispatchEvents.ChannelDelete]: {
13790
14128
  event: "channelDelete",
13791
- build: async (client, data) => [await client.channels.hydrate(data)]
14129
+ build: async (client, data) => [await client.channels._build(data)]
13792
14130
  },
13793
14131
  [GatewayDispatchEvents.ChannelPinsUpdate]: {
13794
14132
  event: "channelPinsUpdate",
@@ -13800,23 +14138,23 @@ const DispatchHandlers = {
13800
14138
  },
13801
14139
  [GatewayDispatchEvents.ThreadCreate]: {
13802
14140
  event: "threadCreate",
13803
- build: async (client, data) => [await client.threads.hydrate(data)]
14141
+ build: async (client, data) => [await client.threads._build(data)]
13804
14142
  },
13805
14143
  [GatewayDispatchEvents.ThreadUpdate]: {
13806
14144
  event: "threadUpdate",
13807
- before: (client, data) => client.threads.get(data.id),
13808
- build: async (client, data, previous) => [previous ?? null, await client.threads.hydrate(data)]
14145
+ before: (client, data) => previousOf(client.threads, data.id),
14146
+ build: async (client, data, previous) => [previous ?? null, await client.threads._build(data)]
13809
14147
  },
13810
14148
  [GatewayDispatchEvents.ThreadDelete]: {
13811
14149
  event: "threadDelete",
13812
- before: (client, data) => client.threads.get(data.id),
14150
+ before: (client, data) => previousOf(client.threads, data.id),
13813
14151
  build: (_client, data, previous) => [previous ?? null, data]
13814
14152
  },
13815
14153
  [GatewayDispatchEvents.ThreadListSync]: {
13816
14154
  event: "threadListSync",
13817
14155
  build: async (client, data) => [
13818
- await Promise.all(data.threads.map((thread) => client.threads.hydrate(thread))),
13819
- await Promise.all(data.members.map((member) => client.threadMembers.hydrate({
14156
+ await Promise.all(data.threads.map((thread) => client.threads._build(thread))),
14157
+ await Promise.all(data.members.map((member) => client.threadMembers._build({
13820
14158
  ...member,
13821
14159
  guild_id: data.guild_id
13822
14160
  }))),
@@ -13825,43 +14163,43 @@ const DispatchHandlers = {
13825
14163
  },
13826
14164
  [GatewayDispatchEvents.ThreadMemberUpdate]: {
13827
14165
  event: "threadMemberUpdate",
13828
- before: (client, data) => data.id && data.user_id ? client.threadMembers.get(data.id, data.user_id) : Promise.resolve(void 0),
13829
- build: async (client, data, previous) => [previous ?? (data.id && data.user_id ? partialThreadMember(client, data.id, data.user_id, data.guild_id) : null), await client.threadMembers.hydrate(data)]
14166
+ before: (client, data) => data.id && data.user_id ? previousOf(client.threadMembers, data.id, data.user_id) : Promise.resolve(void 0),
14167
+ build: async (client, data, previous) => [previous ?? (data.id && data.user_id ? partialThreadMember(client, data.id, data.user_id, data.guild_id) : null), await client.threadMembers._build(data)]
13830
14168
  },
13831
14169
  [GatewayDispatchEvents.ThreadMembersUpdate]: {
13832
14170
  event: "threadMembersUpdate",
13833
14171
  before: async (client, data) => {
13834
- return (await Promise.all((data.removed_member_ids ?? []).map((userId) => client.threadMembers.get(data.id, userId)))).filter((member) => member !== void 0);
14172
+ return (await Promise.all((data.removed_member_ids ?? []).map((userId) => previousOf(client.threadMembers, data.id, userId)))).filter((member) => member !== void 0);
13835
14173
  },
13836
14174
  build: async (client, data, previous) => [
13837
- await Promise.all((data.added_members ?? []).map((member) => client.threadMembers.hydrate({
14175
+ await Promise.all((data.added_members ?? []).map((member) => client.threadMembers._build({
13838
14176
  ...member,
13839
14177
  id: data.id,
13840
14178
  guild_id: data.guild_id
13841
14179
  }))),
13842
14180
  withPartials(previous ?? [], data.removed_member_ids ?? [], (userId) => partialThreadMember(client, data.id, userId, data.guild_id)),
13843
- await cachedOrUndefined(client.threads.get(data.id)) ?? null,
14181
+ await cachedOrUndefined(() => client.threads.cache.get(data.id)) ?? null,
13844
14182
  data
13845
14183
  ]
13846
14184
  },
13847
14185
  [GatewayDispatchEvents.MessageCreate]: {
13848
14186
  event: "messageCreate",
13849
- build: async (client, data) => [await client.messages.hydrate(data)]
14187
+ build: async (client, data) => [await client.messages._build(data)]
13850
14188
  },
13851
14189
  [GatewayDispatchEvents.MessageUpdate]: {
13852
14190
  event: "messageUpdate",
13853
- before: (client, data) => client.messages.get(data.channel_id, data.id),
13854
- build: async (client, data, previous) => [previous ?? partialMessage(client, data.channel_id, data.id, data.guild_id), await client.messages.hydrate(data)]
14191
+ before: (client, data) => previousOf(client.messages, data.channel_id, data.id),
14192
+ build: async (client, data, previous) => [previous ?? partialMessage(client, data.channel_id, data.id, data.guild_id), await client.messages._build(data)]
13855
14193
  },
13856
14194
  [GatewayDispatchEvents.MessageDelete]: {
13857
14195
  event: "messageDelete",
13858
- before: (client, data) => client.messages.get(data.channel_id, data.id),
14196
+ before: (client, data) => previousOf(client.messages, data.channel_id, data.id),
13859
14197
  build: (client, data, previous) => [previous ?? partialMessage(client, data.channel_id, data.id, data.guild_id), data]
13860
14198
  },
13861
14199
  [GatewayDispatchEvents.MessageDeleteBulk]: {
13862
14200
  event: "messageDeleteBulk",
13863
14201
  before: async (client, data) => {
13864
- return (await Promise.all(data.ids.map((id) => client.messages.get(data.channel_id, id)))).filter((message) => message !== void 0);
14202
+ return (await Promise.all(data.ids.map((id) => previousOf(client.messages, data.channel_id, id)))).filter((message) => message !== void 0);
13865
14203
  },
13866
14204
  build: (client, data, previous) => [withPartials(previous ?? [], data.ids, (id) => partialMessage(client, data.channel_id, id, data.guild_id)), data]
13867
14205
  },
@@ -13869,7 +14207,7 @@ const DispatchHandlers = {
13869
14207
  event: "messageReactionAdd",
13870
14208
  build: async (client, data) => [
13871
14209
  await reactionOf(client, data),
13872
- await cachedOrUndefined(client.users.get(data.user_id)) ?? partialUser(client, data.user_id),
14210
+ await cachedOrUndefined(() => client.users.cache.get(data.user_id)) ?? partialUser(client, data.user_id),
13873
14211
  {
13874
14212
  userId: data.user_id,
13875
14213
  type: data.type,
@@ -13881,7 +14219,7 @@ const DispatchHandlers = {
13881
14219
  event: "messageReactionRemove",
13882
14220
  build: async (client, data) => [
13883
14221
  await reactionOf(client, data),
13884
- await cachedOrUndefined(client.users.get(data.user_id)) ?? partialUser(client, data.user_id),
14222
+ await cachedOrUndefined(() => client.users.cache.get(data.user_id)) ?? partialUser(client, data.user_id),
13885
14223
  {
13886
14224
  userId: data.user_id,
13887
14225
  type: data.type,
@@ -13891,16 +14229,16 @@ const DispatchHandlers = {
13891
14229
  },
13892
14230
  [GatewayDispatchEvents.MessageReactionRemoveAll]: {
13893
14231
  event: "messageReactionRemoveAll",
13894
- before: async (client, data) => (await client.messages.get(data.channel_id, data.message_id))?.reactions.cache ?? [],
14232
+ before: async (client, data) => (await previousOf(client.messages, data.channel_id, data.message_id))?.reactions.cache ?? [],
13895
14233
  build: async (client, data, previous) => [
13896
- await cachedOrUndefined(client.messages.get(data.channel_id, data.message_id)) ?? partialMessage(client, data.channel_id, data.message_id, data.guild_id),
14234
+ await cachedOrUndefined(() => cachedOf(client.messages, data.channel_id, data.message_id)) ?? partialMessage(client, data.channel_id, data.message_id, data.guild_id),
13897
14235
  previous ?? [],
13898
14236
  data
13899
14237
  ]
13900
14238
  },
13901
14239
  [GatewayDispatchEvents.MessageReactionRemoveEmoji]: {
13902
14240
  event: "messageReactionRemoveEmoji",
13903
- before: async (client, data) => (await client.messages.get(data.channel_id, data.message_id))?.reactions.resolve(data.emoji) ?? void 0,
14241
+ before: async (client, data) => (await previousOf(client.messages, data.channel_id, data.message_id))?.reactions.resolve(data.emoji) ?? void 0,
13904
14242
  build: async (client, data, previous) => [previous ?? await partialReaction(client, data)]
13905
14243
  },
13906
14244
  [GatewayDispatchEvents.MessagePollVoteAdd]: {
@@ -13913,25 +14251,25 @@ const DispatchHandlers = {
13913
14251
  },
13914
14252
  [GatewayDispatchEvents.GuildMemberAdd]: {
13915
14253
  event: "guildMemberAdd",
13916
- build: async (client, data) => [await client.members.hydrate(data)]
14254
+ build: async (client, data) => [await client.members._build(data)]
13917
14255
  },
13918
14256
  [GatewayDispatchEvents.GuildMemberUpdate]: {
13919
14257
  event: "guildMemberUpdate",
13920
- before: (client, data) => client.members.get(data.guild_id, data.user.id),
13921
- build: async (client, data, previous) => [previous ?? partialMember(client, data.guild_id, { id: data.user.id }), await cachedOrUndefined(client.members.get(data.guild_id, data.user.id)) ?? await client.members.hydrate(data)]
14258
+ before: (client, data) => previousOf(client.members, data.guild_id, data.user.id),
14259
+ build: async (client, data, previous) => [previous ?? partialMember(client, data.guild_id, { id: data.user.id }), await cachedOrUndefined(() => cachedOf(client.members, data.guild_id, data.user.id)) ?? await client.members._build(data)]
13922
14260
  },
13923
14261
  [GatewayDispatchEvents.GuildMemberRemove]: {
13924
14262
  event: "guildMemberRemove",
13925
- before: (client, data) => client.members.get(data.guild_id, data.user.id),
14263
+ before: (client, data) => previousOf(client.members, data.guild_id, data.user.id),
13926
14264
  build: (client, data, previous) => [previous ?? partialMember(client, data.guild_id, data.user), data]
13927
14265
  },
13928
14266
  [GatewayDispatchEvents.GuildMembersChunk]: {
13929
14267
  event: "guildMembersChunk",
13930
14268
  build: async (client, data) => {
13931
- const [members, guild] = await Promise.all([Promise.all(data.members.map((member) => client.members.hydrate({
14269
+ const [members, guild] = await Promise.all([Promise.all(data.members.map((member) => client.members._build({
13932
14270
  ...member,
13933
14271
  guild_id: data.guild_id
13934
- }))), cachedOrUndefined(client.guilds.get(data.guild_id))]);
14272
+ }))), cachedOrUndefined(() => client.guilds.cache.get(data.guild_id))]);
13935
14273
  client.members.handleChunk(members, data);
13936
14274
  return [
13937
14275
  members,
@@ -13942,31 +14280,31 @@ const DispatchHandlers = {
13942
14280
  },
13943
14281
  [GatewayDispatchEvents.GuildRoleCreate]: {
13944
14282
  event: "guildRoleCreate",
13945
- build: async (client, data) => [await client.roles.hydrate({
14283
+ build: async (client, data) => [await client.roles._build({
13946
14284
  ...data.role,
13947
14285
  guild_id: data.guild_id
13948
14286
  })]
13949
14287
  },
13950
14288
  [GatewayDispatchEvents.GuildRoleUpdate]: {
13951
14289
  event: "guildRoleUpdate",
13952
- before: (client, data) => client.roles.get(data.guild_id, data.role.id),
13953
- build: async (client, data, previous) => [previous ?? null, await client.roles.hydrate({
14290
+ before: (client, data) => previousOf(client.roles, data.guild_id, data.role.id),
14291
+ build: async (client, data, previous) => [previous ?? null, await client.roles._build({
13954
14292
  ...data.role,
13955
14293
  guild_id: data.guild_id
13956
14294
  })]
13957
14295
  },
13958
14296
  [GatewayDispatchEvents.GuildRoleDelete]: {
13959
14297
  event: "guildRoleDelete",
13960
- before: (client, data) => client.roles.get(data.guild_id, data.role_id),
14298
+ before: (client, data) => previousOf(client.roles, data.guild_id, data.role_id),
13961
14299
  build: (_client, data, previous) => [previous ?? null, data]
13962
14300
  },
13963
14301
  [GatewayDispatchEvents.InviteCreate]: {
13964
14302
  event: "inviteCreate",
13965
- build: async (client, data) => [data.guild_id ? await client.guilds.invites(data.guild_id).hydrate(data) : bindClient(new GuildInvite(data, { channel: await cachedOrUndefined(client.channels.get(data.channel_id)) ?? null }), client)]
14303
+ build: async (client, data) => [data.guild_id ? await client.guilds.invites(data.guild_id)._build(data) : bindClient(new GuildInvite(data, { channel: await cachedOrUndefined(() => client.channels.cache.get(data.channel_id)) ?? null }), client)]
13966
14304
  },
13967
14305
  [GatewayDispatchEvents.InviteDelete]: {
13968
14306
  event: "inviteDelete",
13969
- before: async (client, data) => data.guild_id ? client.guilds.invites(data.guild_id).get(data.code) : void 0,
14307
+ before: async (client, data) => data.guild_id ? previousOf(client.guilds.invites(data.guild_id), data.code) : void 0,
13970
14308
  build: (_client, data, previous) => [previous ?? null, data]
13971
14309
  },
13972
14310
  [GatewayDispatchEvents.TypingStart]: {
@@ -13975,99 +14313,100 @@ const DispatchHandlers = {
13975
14313
  },
13976
14314
  [GatewayDispatchEvents.VoiceStateUpdate]: {
13977
14315
  event: "voiceStateUpdate",
13978
- before: async (client, data) => data.guild_id ? client.voiceStates.get(data.guild_id, data.user_id) : void 0,
13979
- build: async (client, data, previous) => [previous ?? null, await client.voiceStates.hydrate(data)]
14316
+ before: async (client, data) => data.guild_id ? previousOf(client.voiceStates, data.guild_id, data.user_id) : void 0,
14317
+ build: async (client, data, previous) => [previous ?? null, await client.voiceStates._build(data)]
13980
14318
  },
13981
14319
  [GatewayDispatchEvents.PresenceUpdate]: {
13982
14320
  event: "presenceUpdate",
13983
- before: (client, data) => client.presences.get(data.guild_id, data.user.id),
13984
- build: async (client, data, previous) => [previous ?? null, await cachedOrUndefined(client.presences.get(data.guild_id, data.user.id)) ?? await client.presences.hydrate(data)]
14321
+ before: (client, data) => previousOf(client.presences, data.guild_id, data.user.id),
14322
+ build: async (client, data, previous) => [previous ?? null, await cachedOrUndefined(() => cachedOf(client.presences, data.guild_id, data.user.id)) ?? await client.presences._build(data)]
13985
14323
  },
13986
14324
  [GatewayDispatchEvents.GuildScheduledEventCreate]: {
13987
14325
  event: "guildScheduledEventCreate",
13988
- build: async (client, data) => [await client.guilds.scheduledEvents(data.guild_id).hydrate(data)]
14326
+ build: async (client, data) => [await client.guilds.scheduledEvents(data.guild_id)._build(data)]
13989
14327
  },
13990
14328
  [GatewayDispatchEvents.GuildScheduledEventUpdate]: {
13991
14329
  event: "guildScheduledEventUpdate",
13992
- before: (client, data) => client.guilds.scheduledEvents(data.guild_id).get(data.id),
13993
- build: async (client, data, previous) => [previous ?? partialScheduledEvent(client, data.guild_id, data.id), await client.guilds.scheduledEvents(data.guild_id).hydrate(data)]
14330
+ before: (client, data) => previousOf(client.guilds.scheduledEvents(data.guild_id), data.id),
14331
+ build: async (client, data, previous) => [previous ?? partialScheduledEvent(client, data.guild_id, data.id), await client.guilds.scheduledEvents(data.guild_id)._build(data)]
13994
14332
  },
13995
14333
  [GatewayDispatchEvents.GuildScheduledEventDelete]: {
13996
14334
  event: "guildScheduledEventDelete",
13997
- build: async (client, data) => [await client.guilds.scheduledEvents(data.guild_id).hydrate(data)]
14335
+ build: async (client, data) => [await client.guilds.scheduledEvents(data.guild_id)._build(data)]
13998
14336
  },
13999
14337
  [GatewayDispatchEvents.GuildScheduledEventUserAdd]: {
14000
14338
  event: "guildScheduledEventUserAdd",
14001
14339
  build: async (client, data) => [
14002
- await cachedOrUndefined(client.guilds.scheduledEvents(data.guild_id).get(data.guild_scheduled_event_id)) ?? partialScheduledEvent(client, data.guild_id, data.guild_scheduled_event_id),
14003
- await cachedOrUndefined(client.users.get(data.user_id)) ?? partialUser(client, data.user_id),
14340
+ await cachedOrUndefined(() => cachedOf(client.guilds.scheduledEvents(data.guild_id), data.guild_scheduled_event_id)) ?? partialScheduledEvent(client, data.guild_id, data.guild_scheduled_event_id),
14341
+ await cachedOrUndefined(() => client.users.cache.get(data.user_id)) ?? partialUser(client, data.user_id),
14004
14342
  data
14005
14343
  ]
14006
14344
  },
14007
14345
  [GatewayDispatchEvents.GuildScheduledEventUserRemove]: {
14008
14346
  event: "guildScheduledEventUserRemove",
14009
14347
  build: async (client, data) => [
14010
- await cachedOrUndefined(client.guilds.scheduledEvents(data.guild_id).get(data.guild_scheduled_event_id)) ?? partialScheduledEvent(client, data.guild_id, data.guild_scheduled_event_id),
14011
- await cachedOrUndefined(client.users.get(data.user_id)) ?? partialUser(client, data.user_id),
14348
+ await cachedOrUndefined(() => cachedOf(client.guilds.scheduledEvents(data.guild_id), data.guild_scheduled_event_id)) ?? partialScheduledEvent(client, data.guild_id, data.guild_scheduled_event_id),
14349
+ await cachedOrUndefined(() => client.users.cache.get(data.user_id)) ?? partialUser(client, data.user_id),
14012
14350
  data
14013
14351
  ]
14014
14352
  },
14015
14353
  [GatewayDispatchEvents.StageInstanceCreate]: {
14016
14354
  event: "stageInstanceCreate",
14017
- build: async (client, data) => [await client.guilds.stageInstances(data.guild_id).hydrate(data)]
14355
+ build: async (client, data) => [await client.guilds.stageInstances(data.guild_id)._build(data)]
14018
14356
  },
14019
14357
  [GatewayDispatchEvents.StageInstanceUpdate]: {
14020
14358
  event: "stageInstanceUpdate",
14021
- before: (client, data) => client.guilds.stageInstances(data.guild_id).get(data.channel_id),
14022
- build: async (client, data, previous) => [previous ?? null, await client.guilds.stageInstances(data.guild_id).hydrate(data)]
14359
+ before: (client, data) => previousOf(client.guilds.stageInstances(data.guild_id), data.channel_id),
14360
+ build: async (client, data, previous) => [previous ?? null, await client.guilds.stageInstances(data.guild_id)._build(data)]
14023
14361
  },
14024
14362
  [GatewayDispatchEvents.StageInstanceDelete]: {
14025
14363
  event: "stageInstanceDelete",
14026
- build: async (client, data) => [await client.guilds.stageInstances(data.guild_id).hydrate(data)]
14364
+ build: async (client, data) => [await client.guilds.stageInstances(data.guild_id)._build(data)]
14027
14365
  },
14028
14366
  [GatewayDispatchEvents.GuildSoundboardSoundCreate]: {
14029
14367
  event: "guildSoundboardSoundCreate",
14030
- build: async (client, data) => [await client.guilds.soundboardSounds(data.guild_id).hydrate(data)]
14368
+ build: async (client, data) => [await client.guilds.soundboardSounds(data.guild_id)._build(data)]
14031
14369
  },
14032
14370
  [GatewayDispatchEvents.GuildSoundboardSoundUpdate]: {
14033
14371
  event: "guildSoundboardSoundUpdate",
14034
- before: (client, data) => client.guilds.soundboardSounds(data.guild_id).get(data.sound_id),
14035
- build: async (client, data, previous) => [previous ?? partialSoundboardSound(client, data.guild_id, data.sound_id), await client.guilds.soundboardSounds(data.guild_id).hydrate(data)]
14372
+ before: (client, data) => previousOf(client.guilds.soundboardSounds(data.guild_id), data.sound_id),
14373
+ build: async (client, data, previous) => [previous ?? partialSoundboardSound(client, data.guild_id, data.sound_id), await client.guilds.soundboardSounds(data.guild_id)._build(data)]
14036
14374
  },
14037
14375
  [GatewayDispatchEvents.GuildSoundboardSoundDelete]: {
14038
14376
  event: "guildSoundboardSoundDelete",
14039
- before: (client, data) => client.guilds.soundboardSounds(data.guild_id).get(data.sound_id),
14377
+ before: (client, data) => previousOf(client.guilds.soundboardSounds(data.guild_id), data.sound_id),
14040
14378
  build: (client, data, previous) => [previous ?? partialSoundboardSound(client, data.guild_id, data.sound_id), data]
14041
14379
  },
14042
14380
  [GatewayDispatchEvents.GuildSoundboardSoundsUpdate]: {
14043
14381
  event: "guildSoundboardSoundsUpdate",
14044
14382
  build: async (client, data) => {
14045
14383
  const sounds = client.guilds.soundboardSounds(data.guild_id);
14046
- return [await Promise.all(data.soundboard_sounds.map((sound) => sounds.hydrate(sound))), data.guild_id];
14384
+ return [await Promise.all(data.soundboard_sounds.map((sound) => sounds._build(sound))), data.guild_id];
14047
14385
  }
14048
14386
  },
14049
14387
  [GatewayDispatchEvents.SoundboardSounds]: {
14050
14388
  event: "soundboardSounds",
14051
14389
  build: async (client, data) => {
14052
14390
  const sounds = client.guilds.soundboardSounds(data.guild_id);
14053
- return [await Promise.all(data.soundboard_sounds.map((sound) => sounds.hydrate(sound))), data.guild_id];
14391
+ return [await Promise.all(data.soundboard_sounds.map((sound) => sounds._build(sound))), data.guild_id];
14054
14392
  }
14055
14393
  },
14056
14394
  [GatewayDispatchEvents.GuildBanAdd]: {
14057
14395
  event: "guildBanAdd",
14058
- build: async (client, data) => [await client.guilds.bans(data.guild_id).hydrate(data)]
14396
+ build: async (client, data) => [await client.guilds.bans(data.guild_id)._build(data)]
14059
14397
  },
14060
14398
  [GatewayDispatchEvents.GuildBanRemove]: {
14061
14399
  event: "guildBanRemove",
14062
- before: (client, data) => client.guilds.bans(data.guild_id).get(data.user.id),
14063
- build: async (client, data, previous) => [previous ?? await client.guilds.bans(data.guild_id).hydrate(data)]
14400
+ before: (client, data) => previousOf(client.guilds.bans(data.guild_id), data.user.id),
14401
+ build: async (client, data, previous) => [previous ?? await client.guilds.bans(data.guild_id)._build(data)]
14064
14402
  },
14065
14403
  [GatewayDispatchEvents.GuildAuditLogEntryCreate]: {
14066
14404
  event: "guildAuditLogEntryCreate",
14067
14405
  build: async (client, data) => {
14406
+ const { user_id: userId } = data;
14068
14407
  const [executor, guild, target] = await Promise.all([
14069
- data.user_id ? cachedOrUndefined(client.users.get(data.user_id)) : void 0,
14070
- cachedOrUndefined(client.guilds.get(data.guild_id)),
14408
+ userId ? cachedOrUndefined(() => client.users.cache.get(userId)) : void 0,
14409
+ cachedOrUndefined(() => client.guilds.cache.get(data.guild_id)),
14071
14410
  resolveAuditLogTarget(client, data)
14072
14411
  ]);
14073
14412
  return [bindClient(new GuildAuditLogsEntry(data, {
@@ -14079,44 +14418,45 @@ const DispatchHandlers = {
14079
14418
  },
14080
14419
  [GatewayDispatchEvents.AutoModerationRuleCreate]: {
14081
14420
  event: "autoModerationRuleCreate",
14082
- build: async (client, data) => [await client.guilds.autoModerationRules(data.guild_id).hydrate(data)]
14421
+ build: async (client, data) => [await client.guilds.autoModerationRules(data.guild_id)._build(data)]
14083
14422
  },
14084
14423
  [GatewayDispatchEvents.AutoModerationRuleUpdate]: {
14085
14424
  event: "autoModerationRuleUpdate",
14086
- before: (client, data) => client.guilds.autoModerationRules(data.guild_id).get(data.id),
14087
- build: async (client, data, previous) => [previous ?? null, await client.guilds.autoModerationRules(data.guild_id).hydrate(data)]
14425
+ before: (client, data) => previousOf(client.guilds.autoModerationRules(data.guild_id), data.id),
14426
+ build: async (client, data, previous) => [previous ?? null, await client.guilds.autoModerationRules(data.guild_id)._build(data)]
14088
14427
  },
14089
14428
  [GatewayDispatchEvents.AutoModerationRuleDelete]: {
14090
14429
  event: "autoModerationRuleDelete",
14091
- build: async (client, data) => [await client.guilds.autoModerationRules(data.guild_id).hydrate(data)]
14430
+ build: async (client, data) => [await client.guilds.autoModerationRules(data.guild_id)._build(data)]
14092
14431
  },
14093
14432
  [GatewayDispatchEvents.GuildIntegrationsUpdate]: {
14094
14433
  event: "guildIntegrationsUpdate",
14095
- build: async (client, data) => [await cachedOrUndefined(client.guilds.get(data.guild_id)) ?? null, data]
14434
+ build: async (client, data) => [await cachedOrUndefined(() => client.guilds.cache.get(data.guild_id)) ?? null, data]
14096
14435
  },
14097
14436
  [GatewayDispatchEvents.IntegrationCreate]: {
14098
14437
  event: "integrationCreate",
14099
- build: async (client, data) => [await client.guilds.integrations(data.guild_id).hydrate(data)]
14438
+ build: async (client, data) => [await client.guilds.integrations(data.guild_id)._build(data)]
14100
14439
  },
14101
14440
  [GatewayDispatchEvents.IntegrationUpdate]: {
14102
14441
  event: "integrationUpdate",
14103
- before: (client, data) => client.guilds.integrations(data.guild_id).get(data.id),
14104
- build: async (client, data, previous) => [previous ?? null, await client.guilds.integrations(data.guild_id).hydrate(data)]
14442
+ before: (client, data) => previousOf(client.guilds.integrations(data.guild_id), data.id),
14443
+ build: async (client, data, previous) => [previous ?? null, await client.guilds.integrations(data.guild_id)._build(data)]
14105
14444
  },
14106
14445
  [GatewayDispatchEvents.IntegrationDelete]: {
14107
14446
  event: "integrationDelete",
14108
- before: (client, data) => client.guilds.integrations(data.guild_id).get(data.id),
14447
+ before: (client, data) => previousOf(client.guilds.integrations(data.guild_id), data.id),
14109
14448
  build: (_client, data, previous) => [previous ?? null, data]
14110
14449
  },
14111
14450
  [GatewayDispatchEvents.AutoModerationActionExecution]: {
14112
14451
  event: "autoModerationActionExecution",
14113
14452
  build: async (client, data) => {
14453
+ const { channel_id: channelId } = data;
14114
14454
  const [user, guild, member, channel, autoModerationRule] = await Promise.all([
14115
- cachedOrUndefined(client.users.get(data.user_id)),
14116
- cachedOrUndefined(client.guilds.get(data.guild_id)),
14117
- cachedOrUndefined(client.members.get(data.guild_id, data.user_id)),
14118
- data.channel_id ? cachedOrUndefined(client.channels.get(data.channel_id)) : void 0,
14119
- cachedOrUndefined(client.guilds.autoModerationRules(data.guild_id).get(data.rule_id))
14455
+ cachedOrUndefined(() => client.users.cache.get(data.user_id)),
14456
+ cachedOrUndefined(() => client.guilds.cache.get(data.guild_id)),
14457
+ cachedOrUndefined(() => cachedOf(client.members, data.guild_id, data.user_id)),
14458
+ channelId ? cachedOrUndefined(() => client.channels.cache.get(channelId)) : void 0,
14459
+ cachedOrUndefined(() => cachedOf(client.guilds.autoModerationRules(data.guild_id), data.rule_id))
14120
14460
  ]);
14121
14461
  return [bindClient(new AutoModerationActionExecution(data, {
14122
14462
  user: user ?? null,
@@ -14133,13 +14473,13 @@ const DispatchHandlers = {
14133
14473
  },
14134
14474
  [GatewayDispatchEvents.UserUpdate]: {
14135
14475
  event: "userUpdate",
14136
- before: (client, data) => client.users.get(data.id),
14476
+ before: (client, data) => previousOf(client.users, data.id),
14137
14477
  build: async (client, data, previous) => {
14138
14478
  if (client.user?.id === data.id) {
14139
14479
  client.user[kPatch](data);
14140
14480
  return [previous ?? partialUser(client, data.id), client.user];
14141
14481
  }
14142
- return [previous ?? partialUser(client, data.id), await client.users.hydrate(data)];
14482
+ return [previous ?? partialUser(client, data.id), await client.users._build(data)];
14143
14483
  }
14144
14484
  }
14145
14485
  };
@@ -14155,7 +14495,7 @@ const MultiDispatchHandlers = {
14155
14495
  before: (client, data) => cachedList(client.cache?.emojis, () => client.guilds.emojis(data.guild_id).listCached()),
14156
14496
  emit: async (client, data, previous) => {
14157
14497
  const emojis = client.guilds.emojis(data.guild_id);
14158
- const current = await Promise.all(data.emojis.map((emoji) => emojis.hydrate({
14498
+ const current = await Promise.all(data.emojis.map((emoji) => emojis._build({
14159
14499
  ...emoji,
14160
14500
  guild_id: data.guild_id
14161
14501
  })));
@@ -14172,7 +14512,7 @@ const MultiDispatchHandlers = {
14172
14512
  before: (client, data) => cachedList(client.cache?.stickers, () => client.guilds.stickers(data.guild_id).listCached()),
14173
14513
  emit: async (client, data, previous) => {
14174
14514
  const stickers = client.guilds.stickers(data.guild_id);
14175
- const current = await Promise.all(data.stickers.map((sticker) => stickers.hydrate({
14515
+ const current = await Promise.all(data.stickers.map((sticker) => stickers._build({
14176
14516
  ...sticker,
14177
14517
  guild_id: data.guild_id
14178
14518
  })));
@@ -14187,7 +14527,8 @@ const MultiDispatchHandlers = {
14187
14527
  }
14188
14528
  };
14189
14529
  async function cachedList(store, list) {
14190
- return store && isIterableCache(store) ? list() : void 0;
14530
+ if (!store || !isIterableCache(store)) return void 0;
14531
+ return (await list()).map((value) => value[kClone]());
14191
14532
  }
14192
14533
  function diff(previous, current, create, update, remove) {
14193
14534
  const before = new Map(previous.map((value) => [value.id, value]));
@@ -14206,13 +14547,14 @@ function diff(previous, current, create, update, remove) {
14206
14547
  return events;
14207
14548
  }
14208
14549
  async function reactionOf(client, data) {
14209
- const message = await cachedOrUndefined(client.messages.get(data.channel_id, data.message_id));
14550
+ const message = await cachedOrUndefined(() => cachedOf(client.messages, data.channel_id, data.message_id));
14210
14551
  if (!message) return partialReaction(client, data);
14211
14552
  return message.reactions.resolve(data.emoji) ?? partialReaction(client, data, true, message);
14212
14553
  }
14213
14554
  async function partialReaction(client, data, emptied = false, message = partialMessage(client, data.channel_id, data.message_id, data.guild_id)) {
14214
14555
  const { guild_id: guildId, emoji } = data;
14215
- const cachedEmoji = guildId && emoji.id ? await cachedOrUndefined(client.guilds.emojis(guildId).get(emoji.id)) : void 0;
14556
+ const emojiId = emoji.id;
14557
+ const cachedEmoji = guildId && emojiId ? await cachedOrUndefined(() => cachedOf(client.guilds.emojis(guildId), emojiId)) : void 0;
14216
14558
  return bindClient(new MessageReaction({
14217
14559
  channel_id: data.channel_id,
14218
14560
  message_id: data.message_id,
@@ -14233,7 +14575,7 @@ async function partialReaction(client, data, emptied = false, message = partialM
14233
14575
  }), client);
14234
14576
  }
14235
14577
  async function pollAnswerOf(client, data) {
14236
- const message = await cachedOrUndefined(client.messages.get(data.channel_id, data.message_id));
14578
+ const message = await cachedOrUndefined(() => cachedOf(client.messages, data.channel_id, data.message_id));
14237
14579
  return message?.poll?.answers.find((answer) => answer.id === data.answer_id) ?? bindClient(new PollAnswer({
14238
14580
  answer_id: data.answer_id,
14239
14581
  poll_media: {},
@@ -14244,13 +14586,13 @@ async function pollAnswerOf(client, data) {
14244
14586
  async function typingOf(client, data) {
14245
14587
  const { guild_id: guildId, member, user_id: userId } = data;
14246
14588
  const [channel, user, guild, resolvedMember] = await Promise.all([
14247
- cachedOrUndefined(client.channels.get(data.channel_id)),
14248
- cachedOrUndefined(member?.user ? client.users.resolveData(member.user) : client.users.get(userId)),
14249
- guildId ? cachedOrUndefined(Promise.resolve(client.guilds._getShallow(guildId))) : void 0,
14250
- guildId ? cachedOrUndefined(member?.user ? client.members.resolveData({
14589
+ cachedOrUndefined(() => client.channels.cache.get(data.channel_id)),
14590
+ cachedOrUndefined(() => member?.user ? client.users._resolveData(member.user) : client.users.cache.get(userId)),
14591
+ guildId ? cachedOrUndefined(() => client.guilds._getShallow(guildId)) : void 0,
14592
+ guildId ? cachedOrUndefined(() => member?.user ? client.members._resolveData({
14251
14593
  ...member,
14252
14594
  guild_id: guildId
14253
- }) : client.members.get(guildId, userId)) : void 0
14595
+ }) : cachedOf(client.members, guildId, userId)) : void 0
14254
14596
  ]);
14255
14597
  return bindClient(new Typing(data, {
14256
14598
  channel: channel ?? (guildId ? null : partialDMChannel(client, data.channel_id, userId)),
@@ -14326,8 +14668,16 @@ function partialDMChannel(client, channelId, recipientId) {
14326
14668
  recipients: [{ id: recipientId }]
14327
14669
  }), client);
14328
14670
  }
14329
- function cachedOrUndefined(read) {
14330
- return read.catch(() => void 0);
14671
+ /**
14672
+ * Resolves a cache read, or `undefined` when the cache cannot be read, so an event can still be built from its
14673
+ * payload. The failure itself was already reported while applying the dispatch.
14674
+ */
14675
+ async function cachedOrUndefined(read) {
14676
+ try {
14677
+ return await read();
14678
+ } catch {
14679
+ return;
14680
+ }
14331
14681
  }
14332
14682
 
14333
14683
  //#endregion
@@ -14562,11 +14912,338 @@ var GatewaySessionMirror = class {
14562
14912
  }
14563
14913
  };
14564
14914
 
14915
+ //#endregion
14916
+ //#region src/util/CollectionCache.ts
14917
+ /**
14918
+ * The default {@link Cache}: an in-memory `Collection` of structure instances, like discord.js's caches.
14919
+ *
14920
+ * @remarks
14921
+ * `add` patches the cached instance in place, so a reference kept by the application sees later updates.
14922
+ *
14923
+ * Every method is synchronous. Being a `Collection`, it also has `find`, `filter`, `map`, ... which return plain
14924
+ * collections. Instances reached by iterating carry the relations of their last `get`.
14925
+ */
14926
+ var CollectionCache = class extends Collection {
14927
+ static get [Symbol.species]() {
14928
+ return Collection;
14929
+ }
14930
+ synchronous = true;
14931
+ construct;
14932
+ /**
14933
+ * The name of the entity this cache holds.
14934
+ */
14935
+ name;
14936
+ #keyOf;
14937
+ #refresh;
14938
+ #maxSize;
14939
+ constructor(creator, name, options = {}) {
14940
+ super();
14941
+ this.construct = creator;
14942
+ this.name = name;
14943
+ this.#keyOf = options.keyOf ?? ((data) => data.id);
14944
+ this.#refresh = options.refresh;
14945
+ this.#maxSize = options.maxSize ?? Infinity;
14946
+ }
14947
+ add(data, overwrite = false) {
14948
+ const key = this.#keyOf(data);
14949
+ const existing = overwrite ? void 0 : super.get(key);
14950
+ if (existing !== void 0) {
14951
+ existing[kPatch](data);
14952
+ return this.#refresh ? this.#refresh(existing) : existing;
14953
+ }
14954
+ const value = this.construct(data);
14955
+ this.set(key, value);
14956
+ return this.#refresh ? this.#refresh(value) : value;
14957
+ }
14958
+ get(key) {
14959
+ const value = super.get(key);
14960
+ return value !== void 0 && this.#refresh ? this.#refresh(value) : value;
14961
+ }
14962
+ set(key, value) {
14963
+ if (this.#maxSize <= 0) return this;
14964
+ if (this.size >= this.#maxSize && !super.has(key)) {
14965
+ const oldest = this.keys().next();
14966
+ if (!oldest.done) super.delete(oldest.value);
14967
+ }
14968
+ return super.set(key, value);
14969
+ }
14970
+ getSize() {
14971
+ return this.size;
14972
+ }
14973
+ };
14974
+
14975
+ //#endregion
14976
+ //#region src/util/EntityStoreCache.ts
14977
+ const unguarded = (_operation, _key, run) => run();
14978
+ /**
14979
+ * A {@link Cache} over a raw `@wolfstar/plugin-cache` store (in memory or Redis): the store holds raw API data, and a
14980
+ * structure is built on every read.
14981
+ *
14982
+ * @remarks
14983
+ * Unlike `CollectionCache`, two reads of the same key return two structures: do not rely on object identity.
14984
+ */
14985
+ var EntityStoreCache = class {
14986
+ construct;
14987
+ /**
14988
+ * The name of the entity this cache holds.
14989
+ */
14990
+ name;
14991
+ /**
14992
+ * The raw store.
14993
+ */
14994
+ store;
14995
+ #keyOf;
14996
+ #hydrate;
14997
+ #guard;
14998
+ #synchronous;
14999
+ constructor(creator, name, options) {
15000
+ this.construct = creator;
15001
+ this.name = name;
15002
+ this.store = options.store;
15003
+ this.#keyOf = options.keyOf;
15004
+ this.#hydrate = options.hydrate ?? creator;
15005
+ this.#guard = options.guard ?? unguarded;
15006
+ this.#synchronous = options.synchronous;
15007
+ }
15008
+ get synchronous() {
15009
+ return this.#synchronous ? this.#synchronous() : this.store.synchronous === true;
15010
+ }
15011
+ add(data, overwrite = false) {
15012
+ const raw = data;
15013
+ const key = this.#keyOf(data);
15014
+ return whenAll([this.#guard("upsert", key, () => this.store.upsert(key, data, { overwrite }), { added: raw })], ([{ added }]) => this.#hydrate(added));
15015
+ }
15016
+ clear() {
15017
+ return this.#guard("clear", null, () => this.store.clear(), void 0);
15018
+ }
15019
+ delete(key) {
15020
+ return this.#guard("delete", key, () => this.store.delete(key), false);
15021
+ }
15022
+ get(key) {
15023
+ return whenAll([this.#guard("get", key, () => this.store.get(key), void 0)], ([raw]) => raw === void 0 ? void 0 : this.#hydrate(raw));
15024
+ }
15025
+ getSize() {
15026
+ return this.#guard("getSize", null, () => this.store.getSize(), 0);
15027
+ }
15028
+ has(key) {
15029
+ return this.#guard("has", key, () => this.store.has(key), false);
15030
+ }
15031
+ set(key, value) {
15032
+ const raw = value.toJSON();
15033
+ return whenAll([this.#guard("set", key, () => this.store.set(key, raw), void 0)], () => this);
15034
+ }
15035
+ };
15036
+
15037
+ //#endregion
15038
+ //#region src/util/entityManagers.ts
15039
+ /**
15040
+ * The entities of `@wolfstar/plugin-cache` a manager builds structures for.
15041
+ *
15042
+ * @internal
15043
+ */
15044
+ const ManagedEntityNames = [
15045
+ "autoModerationRules",
15046
+ "bans",
15047
+ "channels",
15048
+ "emojis",
15049
+ "guilds",
15050
+ "integrations",
15051
+ "invites",
15052
+ "members",
15053
+ "messages",
15054
+ "presences",
15055
+ "roles",
15056
+ "scheduledEvents",
15057
+ "soundboardSounds",
15058
+ "stageInstances",
15059
+ "stickers",
15060
+ "threadMembers",
15061
+ "threads",
15062
+ "users",
15063
+ "voiceStates"
15064
+ ];
15065
+ function guildIdOf(data) {
15066
+ return data.guild_id ?? "";
15067
+ }
15068
+ const managers = {
15069
+ autoModerationRules: (client, data) => client.guilds.autoModerationRules(guildIdOf(data)),
15070
+ bans: (client, data) => client.guilds.bans(guildIdOf(data)),
15071
+ channels: (client) => client.channels,
15072
+ emojis: (client, data) => client.guilds.emojis(guildIdOf(data)),
15073
+ guilds: (client) => client.guilds,
15074
+ integrations: (client, data) => client.guilds.integrations(guildIdOf(data)),
15075
+ invites: (client, data) => client.guilds.invites(guildIdOf(data)),
15076
+ members: (client) => client.members,
15077
+ messages: (client) => client.messages,
15078
+ presences: (client) => client.presences,
15079
+ roles: (client) => client.roles,
15080
+ scheduledEvents: (client, data) => client.guilds.scheduledEvents(guildIdOf(data)),
15081
+ soundboardSounds: (client, data) => client.guilds.soundboardSounds(guildIdOf(data)),
15082
+ stageInstances: (client, data) => client.guilds.stageInstances(guildIdOf(data)),
15083
+ stickers: (client, data) => client.guilds.stickers(guildIdOf(data)),
15084
+ threadMembers: (client) => client.threadMembers,
15085
+ threads: (client) => client.threads,
15086
+ users: (client) => client.users,
15087
+ voiceStates: (client) => client.voiceStates
15088
+ };
15089
+ /**
15090
+ * Gets the manager building the structures of an entity. Guild-scoped managers are created for the guild the data
15091
+ * belongs to.
15092
+ *
15093
+ * @param client The client.
15094
+ * @param name The name of the entity.
15095
+ * @param data The raw data the manager is needed for.
15096
+ * @internal
15097
+ */
15098
+ function managerOf(client, name, data) {
15099
+ return managers[name](client, data);
15100
+ }
15101
+
15102
+ //#endregion
15103
+ //#region src/util/NullCache.ts
15104
+ /**
15105
+ * The {@link Cache} of an entity that is not cached: always empty, writes are dropped.
15106
+ */
15107
+ var NullCache = class {
15108
+ construct;
15109
+ /**
15110
+ * The name of the entity this cache stands for.
15111
+ */
15112
+ name;
15113
+ #hydrate;
15114
+ #synchronous;
15115
+ constructor(creator, name, options = {}) {
15116
+ this.construct = creator;
15117
+ this.name = name;
15118
+ this.#hydrate = options.hydrate ?? creator;
15119
+ this.#synchronous = options.synchronous;
15120
+ }
15121
+ get synchronous() {
15122
+ return this.#synchronous?.() ?? true;
15123
+ }
15124
+ add(data) {
15125
+ return this.#hydrate(data);
15126
+ }
15127
+ clear() {}
15128
+ delete() {
15129
+ return false;
15130
+ }
15131
+ get() {}
15132
+ getSize() {
15133
+ return 0;
15134
+ }
15135
+ has() {
15136
+ return false;
15137
+ }
15138
+ set() {
15139
+ return this;
15140
+ }
15141
+ };
15142
+
15143
+ //#endregion
15144
+ //#region src/util/StructureStoreAdapter.ts
15145
+ function toRaw(value) {
15146
+ return { ...value.toJSON() };
15147
+ }
15148
+ /**
15149
+ * A raw `@wolfstar/plugin-cache` store over a structure {@link Cache}, so that what writes raw data (the gateway
15150
+ * dispatches, their cascades, the policies) works against a cache of structures.
15151
+ *
15152
+ * @remarks
15153
+ * Writes patch the cached instance in place. Time-to-live options are ignored: structure caches have none.
15154
+ *
15155
+ * @internal
15156
+ */
15157
+ var StructureStoreAdapter = class {
15158
+ cache;
15159
+ constructor(cache) {
15160
+ this.cache = cache;
15161
+ }
15162
+ get synchronous() {
15163
+ return this.cache.synchronous;
15164
+ }
15165
+ read(key) {
15166
+ return peekCache(this.cache, key);
15167
+ }
15168
+ get(key) {
15169
+ return whenAll([this.read(key)], ([value]) => value === void 0 ? void 0 : toRaw(value));
15170
+ }
15171
+ /**
15172
+ * Writes an entry. Unlike a raw store's `set`, it merges the value into a cached instance rather than replacing it:
15173
+ * the keys absent from the new value persist.
15174
+ */
15175
+ set(key, value) {
15176
+ return whenAll([this.read(key)], ([existing]) => {
15177
+ const entry = existing === void 0 ? this.cache.construct(value) : existing;
15178
+ if (existing !== void 0) existing[kPatch](value);
15179
+ return whenAll([this.cache.set(key, entry)], () => void 0);
15180
+ });
15181
+ }
15182
+ /**
15183
+ * Merges data into an entry, creating it when it is missing.
15184
+ *
15185
+ * @remarks
15186
+ * A cached instance is always patched in place, with or without `overwrite`: replacing it would leave the
15187
+ * application holding a stale instance. Since a structure's patch merges, an `overwrite` on a structure cache
15188
+ * behaves like {@link StructureStoreAdapter.set}: the keys absent from the new data keep their cached value,
15189
+ * where a raw store would drop them.
15190
+ */
15191
+ upsert(key, data, _options) {
15192
+ return whenAll([this.read(key)], ([existing]) => {
15193
+ if (existing === void 0) {
15194
+ const value = this.cache.construct(data);
15195
+ return whenAll([this.cache.set(key, value)], () => ({
15196
+ existing: void 0,
15197
+ added: toRaw(value)
15198
+ }));
15199
+ }
15200
+ const before = toRaw(existing);
15201
+ existing[kPatch](data);
15202
+ return whenAll([this.cache.set(key, existing)], () => ({
15203
+ existing: before,
15204
+ added: toRaw(existing)
15205
+ }));
15206
+ });
15207
+ }
15208
+ has(key) {
15209
+ return this.cache.has(key);
15210
+ }
15211
+ delete(key) {
15212
+ return this.cache.delete(key);
15213
+ }
15214
+ clear() {
15215
+ return this.cache.clear();
15216
+ }
15217
+ getSize() {
15218
+ return this.cache.getSize();
15219
+ }
15220
+ };
15221
+ var IterableStructureStoreAdapter = class extends StructureStoreAdapter {
15222
+ keys() {
15223
+ return [...this.cache.keys()];
15224
+ }
15225
+ values() {
15226
+ return [...this.cache.values()].map((value) => toRaw(value));
15227
+ }
15228
+ entries() {
15229
+ return [...this.cache.entries()].map(([key, value]) => [key, toRaw(value)]);
15230
+ }
15231
+ };
15232
+ /**
15233
+ * Creates the raw store of a structure cache, enumerable when the cache is a `Map` (e.g. `CollectionCache`).
15234
+ *
15235
+ * @param cache The structure cache.
15236
+ * @internal
15237
+ */
15238
+ function createStructureStoreAdapter(cache) {
15239
+ return cache instanceof Map ? new IterableStructureStoreAdapter(cache) : new StructureStoreAdapter(cache);
15240
+ }
15241
+
14565
15242
  //#endregion
14566
15243
  //#region src/GatewayClient.ts
14567
15244
  /**
14568
15245
  * A {@link Client} that, on top of serving HTTP interactions, connects to the Discord gateway, writes every dispatch
14569
- * into an optional {@link Cache}, and emits {@link GatewayEventMap} events carrying structures.
15246
+ * into its cache, and emits {@link GatewayEventMap} events carrying structures.
14570
15247
  *
14571
15248
  * @example
14572
15249
  * ```typescript
@@ -14586,7 +15263,8 @@ var GatewaySessionMirror = class {
14586
15263
  */
14587
15264
  var GatewayClient = class extends Client {
14588
15265
  /**
14589
- * The cache every dispatch is written into, if any.
15266
+ * The raw cache every dispatch is written into, if any: the `@wolfstar/plugin-cache` cache passed as
15267
+ * {@link GatewayClientOptions.cache}, or a raw view of the managers' caches of instances.
14590
15268
  */
14591
15269
  cache;
14592
15270
  /**
@@ -14656,6 +15334,12 @@ var GatewayClient = class extends Client {
14656
15334
  */
14657
15335
  clientReadyTimestamp = null;
14658
15336
  #queue = new DispatchQueue();
15337
+ #caches = /* @__PURE__ */ new Map();
15338
+ #cacheConstructor;
15339
+ #cacheOptions;
15340
+ #stores;
15341
+ #storesSynchronous;
15342
+ #policies;
14659
15343
  #shardCount;
14660
15344
  #intents;
14661
15345
  #token;
@@ -14668,7 +15352,14 @@ var GatewayClient = class extends Client {
14668
15352
  super(options);
14669
15353
  container.gatewayClient = this;
14670
15354
  this.rest = container.rest;
14671
- this.cache = resolveCache(options);
15355
+ const storeBacked = Boolean(options.cache || options.makeCache);
15356
+ if ((options.cacheConstructor || options.cacheOptions) && storeBacked) throw new GatewayTypeError("ClientCacheConflict");
15357
+ this.#cacheOptions = options.cacheOptions ?? {};
15358
+ const stores = resolveCache(options);
15359
+ this.#stores = stores;
15360
+ this.#storesSynchronous = Object.values(stores ?? {}).every((store) => store.synchronous === true);
15361
+ this.#cacheConstructor = options.cache === null || storeBacked ? null : options.cacheConstructor ?? CollectionCache;
15362
+ this.#policies = this.#cacheConstructor ? options.policies : void 0;
14672
15363
  this.cacheErrors = options.cacheErrors ?? "miss";
14673
15364
  this.cacheFailure = options.cacheFailure ?? "skip";
14674
15365
  this.dispatchTimeout = options.dispatchTimeout === void 0 ? 3e4 : options.dispatchTimeout;
@@ -14689,6 +15380,7 @@ var GatewayClient = class extends Client {
14689
15380
  this.templates = new GuildTemplateManager(this);
14690
15381
  this.voiceStates = new VoiceStateManager(this);
14691
15382
  this.presences = new PresenceManager(this);
15383
+ this.cache = this.#cacheConstructor ? this.#createStructureStores(options.policies) : stores;
14692
15384
  this.gateway = new WebSocketManager({
14693
15385
  ...options.gateway,
14694
15386
  ...this.sessionCallbacks(options),
@@ -14776,6 +15468,96 @@ var GatewayClient = class extends Client {
14776
15468
  return outcome.value;
14777
15469
  }
14778
15470
  /**
15471
+ * Gets the cache of an entity, building it on first use: the `CacheConstructor` of the discord.js RFC #11426.
15472
+ * Every manager of the same entity shares the same cache.
15473
+ *
15474
+ * @param creator Builds a structure from raw data, for entities the client does not know how to build.
15475
+ * @param name The name of the entity.
15476
+ */
15477
+ CacheConstructor(creator, name) {
15478
+ let cache = this.#caches.get(name);
15479
+ if (cache === void 0) {
15480
+ cache = this.#createCache(creator, name);
15481
+ this.#caches.set(name, cache);
15482
+ }
15483
+ return cache;
15484
+ }
15485
+ /**
15486
+ * Runs a raw store operation, reporting its failure through `cacheError`, see
15487
+ * {@link GatewayClientOptions.cacheErrors}. Synchronous when the operation is.
15488
+ *
15489
+ * @internal
15490
+ */
15491
+ guardCache(entity, operation, key, run, fallback) {
15492
+ const fail = (error) => {
15493
+ this.emit("cacheError", error, {
15494
+ entity,
15495
+ key,
15496
+ operation
15497
+ });
15498
+ if (this.cacheErrors === "throw") throw error;
15499
+ return fallback;
15500
+ };
15501
+ try {
15502
+ const result = run();
15503
+ return isPromiseLike(result) ? result.catch(fail) : result;
15504
+ } catch (error) {
15505
+ return fail(error);
15506
+ }
15507
+ }
15508
+ /**
15509
+ * Gets the `filter` of an entity's policy the managers must apply themselves before writing to its cache, see
15510
+ * {@link GatewayClientOptions.policies}.
15511
+ *
15512
+ * @param name The name of the entity.
15513
+ * @returns The filter, or `undefined` when there is none or when the entity's store applies it already.
15514
+ * @internal
15515
+ */
15516
+ cacheFilter(name) {
15517
+ const policy = this.#policies?.[name];
15518
+ return policy?.filter ? (value, key) => policy.filter(value, key) : void 0;
15519
+ }
15520
+ #createCache(creator, name) {
15521
+ const managed = ManagedEntityNames.includes(name);
15522
+ const construct = managed ? (data) => managerOf(this, name, data)._construct(data) : creator;
15523
+ const hydrate = managed ? (data) => managerOf(this, name, data)._build(data) : creator;
15524
+ const keyOf = managed ? (data) => managerOf(this, name, data).keyOf(data) : (data) => data.id;
15525
+ if (this.#cacheConstructor) {
15526
+ const refresh = (value) => {
15527
+ const refreshed = refreshRelations(value, hydrate);
15528
+ if (isPromiseLike(refreshed)) {
15529
+ refreshed.catch(() => void 0);
15530
+ throw new GatewayTypeError("CacheConstructorAsynchronous", name);
15531
+ }
15532
+ return refreshed;
15533
+ };
15534
+ return new this.#cacheConstructor(construct, name, {
15535
+ keyOf,
15536
+ refresh,
15537
+ ...this.#cacheOptions[name]
15538
+ });
15539
+ }
15540
+ const store = this.#stores?.[name];
15541
+ const synchronous = () => this.#storesSynchronous;
15542
+ if (store === void 0) return new NullCache(construct, name, {
15543
+ hydrate,
15544
+ synchronous
15545
+ });
15546
+ return new EntityStoreCache(construct, name, {
15547
+ store,
15548
+ keyOf,
15549
+ hydrate,
15550
+ synchronous,
15551
+ guard: (operation, key, run, fallback) => this.guardCache(name, operation, key, run, fallback)
15552
+ });
15553
+ }
15554
+ #createStructureStores(policies) {
15555
+ return createCache({
15556
+ policies,
15557
+ makeCache: (name) => ManagedEntityNames.includes(name) ? createStructureStoreAdapter(this.CacheConstructor(() => void 0, name)) : new MemoryEntityCache(this.#cacheOptions[name]?.maxSize ?? Infinity)
15558
+ });
15559
+ }
15560
+ /**
14779
15561
  * Resolves once every dispatch received so far has been processed.
14780
15562
  */
14781
15563
  async idle() {
@@ -14824,10 +15606,10 @@ var GatewayClient = class extends Client {
14824
15606
  guild_scheduled_event_id: options.guildScheduledEventId
14825
15607
  });
14826
15608
  const [guild, channel, inviter, targetUser] = await Promise.all([
14827
- invite.guild ? this.guilds.get(invite.guild.id) : void 0,
14828
- invite.channel ? this.channels.get(invite.channel.id) : void 0,
14829
- invite.inviter ? this.users.resolveData(invite.inviter) : void 0,
14830
- invite.target_user ? this.users.resolveData(invite.target_user) : void 0
15609
+ invite.guild ? this.guilds.cache.get(invite.guild.id) : void 0,
15610
+ invite.channel ? this.channels.cache.get(invite.channel.id) : void 0,
15611
+ invite.inviter ? this.users._resolveData(invite.inviter) : void 0,
15612
+ invite.target_user ? this.users._resolveData(invite.target_user) : void 0
14831
15613
  ]);
14832
15614
  return bindClient(createInvite(invite, {
14833
15615
  guild: guild ?? null,
@@ -14971,8 +15753,9 @@ var GatewayClient = class extends Client {
14971
15753
  }
14972
15754
  }
14973
15755
  async dropUnlistedGuilds(data, shardId) {
14974
- const guilds = this.cache?.guilds;
14975
- if (!guilds || !isIterableCache(guilds)) return;
15756
+ const { cache } = this;
15757
+ const guilds = cache?.guilds;
15758
+ if (!cache || !guilds || !isIterableCache(guilds)) return;
14976
15759
  const cached = await guilds.keys();
14977
15760
  if (cached.length === 0) return;
14978
15761
  const count = data.shard?.[1] ?? this.#shardCount ?? await this.gateway.getShardCount();
@@ -14980,8 +15763,8 @@ var GatewayClient = class extends Client {
14980
15763
  const shardCount = BigInt(count);
14981
15764
  for (const id of cached) {
14982
15765
  if (listed.has(id) || Number((BigInt(id) >> 22n) % shardCount) !== shardId) continue;
14983
- const guild = await this.guilds.get(id) ?? null;
14984
- await applyGatewayDispatch(this.cache, {
15766
+ const guild = await this.guilds.cache.get(id) ?? null;
15767
+ await applyGatewayDispatch(cache, {
14985
15768
  op: GatewayOpcodes.Dispatch,
14986
15769
  s: 0,
14987
15770
  t: GatewayDispatchEvents.GuildDelete,
@@ -15027,8 +15810,8 @@ var GatewayClient = class extends Client {
15027
15810
  }
15028
15811
  };
15029
15812
  /**
15030
- * Builds the cache of a client out of its options: the stores of `makeCache` (or `cache`), wrapped by `policies`.
15031
- * `undefined` when no entity kind is cached.
15813
+ * Builds the raw stores of a client out of its options: the stores of `makeCache` (or `cache`), wrapped by
15814
+ * `policies`. `undefined` when no entity kind is stored, which `cache: null` asks for.
15032
15815
  */
15033
15816
  function resolveCache(options) {
15034
15817
  const { makeCache, cache, policies } = options;
@@ -15097,5 +15880,5 @@ function RegisterAsGatewayListener(event, options = {}) {
15097
15880
  }
15098
15881
 
15099
15882
  //#endregion
15100
- export { Action, ActionRow, ActionsManager, Activity, ActivityFlagsBitField, AnnouncementChannel, AnnouncementThreadChannel, AnonymousGuild, ApplicationFlagsBitField, AppliedTagsMixin, Attachment, AttachmentFlagsBitField, AutoModerationActionExecution, AutoModerationRule, AutoModerationRuleManager, BaseChannel, BaseChannelMixin, BaseInvite, CachedManager as BaseManager, CachedManager, BitField, CategoryChannel, Channel, ChannelFlagsBitField, ChannelManager, ChannelMessageManager, ChannelOwnerMixin, ChannelParentMixin, ChannelPermissionMixin, ChannelSelectMenuComponent, ChannelSlowmodeMixin, ChannelThreadManager, ChannelThreadsMixin, ChannelTopicMixin, ChannelWebhooksMixin, CheckboxComponent, CheckboxGroupComponent, ClientUser, Colors, Component, ComponentMixin, ContainerComponent, DMChannel, DMChannelMixin, DispatchAction, DispatchHandlers, DispatchQueue, DispatchTimeoutError, Embed, Emoji, EventGatewayListener, FileComponent, FileUploadComponent, ForumChannel, GatewayClient, GatewayError, GatewayErrorCodes, GatewayErrorMessages, GatewayEvents, GatewayRangeError, GatewaySessionStoreError, GatewayTypeError, GroupDMChannel, GroupDMInvite, GroupDMMixin, Guild, GuildAuditLogsEntry, GuildBan, GuildBanManager, GuildChannelFields, GuildChannelManager, GuildChannelMixin, GuildEmoji, GuildEmojiManager, GuildEmojiRoleManager, GuildIntegrationManager, GuildInvite, GuildInviteManager, GuildManager, GuildMember, GuildMemberFlagsBitField, GuildMemberManager, GuildMemberRoleManager, GuildMembersRateLimitError, GuildMembersTimeoutError, GuildOnboarding, GuildOnboardingPrompt, GuildOnboardingPromptOption, GuildPreview, GuildScheduledEvent, GuildScheduledEventManager, GuildSoundboardSoundManager, GuildStickerManager, GuildTemplate, GuildTemplateManager, GuildTemplatesPattern, Integration, IntentsBitField, InteractiveButtonComponent, InviteGuild, InvitesPattern, LabelComponent, LinkButtonComponent, MediaChannel, MediaGalleryComponent, MediaGalleryItem, MentionableSelectMenuComponent, Message, MessageFlagsBitField, MessageManager, MessageMentions, MessagePayload, MessageReaction, Mixin, MultiDispatchAction, MultiDispatchHandlers, NumberFlagsBitField, Partials, PermissionOverwriteManager, PermissionOverwrites, PermissionsBitField, Poll, PollAnswer, PremiumButtonComponent, Presence, PresenceManager, PrivateThreadChannel, PublicThreadChannel, RadioGroupComponent, ReactionEmoji, ReactionManager, ReactionUserManager, RegisterAsGatewayListener, RichPresenceAssets, Role, RoleFlagsBitField, RoleManager, RoleSelectMenuComponent, SectionComponent, SeparatorComponent, SoundboardSound, StageChannel, StageInstance, StageInstanceManager, Sticker, StickerPack, StringSelectMenuComponent, Structure, StructureMixin, SystemChannelFlagsBitField, TextChannel, TextChannelMixin, TextDisplayComponent, TextInputComponent, ThreadChannelMemberManager, ThreadChannelMixin, ThreadManager, ThreadMember, ThreadMemberManager, ThreadOnlyChannelMixin, ThumbnailComponent, Typing, UnfurledMediaItem, User, UserFlagsBitField, UserManager, UserSelectMenuComponent, VoiceChannel, VoiceChannelMixin, VoiceState, VoiceStateManager, Webhook, WebhookManager, WebhookMixin, WelcomeScreen, Widget, WidgetMember, basename, bindClient, cleanCodeBlockContent, cleanContent, compareRolePositions, computeChannelPermissions, computeGuildPermissions, computePermissionsIn, computePositions, computeTargetPermissions, createChannel, createComponent, createInvite, discordSort, dispatchPartition, findComponentByCustomId, findName, flatten, getGatewayClient, getSortableGroupTypes, initStructure, isDeepEqual, isThreadChannelType, kClient, kClone, kData, kPatch, kPatchRelations, kRelations, makeError, makePlainError, moveElementInArray, parseEmoji, parseWebhookURL, resolveBase64, resolveCode, resolveColor, resolveFile, resolveGuildTemplateCode, resolveId, resolveImage, resolveImageOption, resolveInviteCode, resolveOverwriteOptions, resolvePartialEmoji, resolveSKUId, snakeCase, snowflakeTimestamp, toAPIOverwrite, toChannelBody, toSnakeCase, transformAPIAuditLogChange, transformAPIAutoModerationAction, transformAPIAutoModerationRuleTriggerMetadata, transformAPIAvatarDecorationData, transformAPIChannelMention, transformAPIEmbedAsset, transformAPIEmbedAuthor, transformAPIEmbedFooter, transformAPIGuildDefaultReaction, transformAPIGuildForumTag, transformAPIGuildScheduledEventEntityMetadata, transformAPIGuildScheduledEventRecurrenceRule, transformAPIIncidentsData, transformAPIMessageActivity, transformAPIMessageCall, transformAPIMessageInteractionMetadata, transformAPIMessageReference, transformAPIRoleSubscriptionData, transformAPIRoleTags, transformAPIUserPrimaryGuild, transformAutoModerationAction, transformAutoModerationRuleTriggerMetadata, transformCollectibles, transformGuildDefaultReaction, transformGuildForumTag, transformGuildScheduledEventRecurrenceRule, transformResolved, verifyString };
15883
+ export { Action, ActionRow, ActionsManager, Activity, ActivityFlagsBitField, AnnouncementChannel, AnnouncementThreadChannel, AnonymousGuild, ApplicationFlagsBitField, AppliedTagsMixin, Attachment, AttachmentFlagsBitField, AutoModerationActionExecution, AutoModerationRule, AutoModerationRuleManager, BaseChannel, BaseChannelMixin, BaseInvite, BaseManager, BitField, CachedManager, CategoryChannel, Channel, ChannelFlagsBitField, ChannelManager, ChannelMessageManager, ChannelOwnerMixin, ChannelParentMixin, ChannelPermissionMixin, ChannelSelectMenuComponent, ChannelSlowmodeMixin, ChannelThreadManager, ChannelThreadsMixin, ChannelTopicMixin, ChannelWebhooksMixin, CheckboxComponent, CheckboxGroupComponent, ClientUser, CollectionCache, Colors, Component, ComponentMixin, ContainerComponent, DMChannel, DMChannelMixin, DataManager, DispatchAction, DispatchHandlers, DispatchQueue, DispatchTimeoutError, Embed, Emoji, EntityStoreCache, EventGatewayListener, FileComponent, FileUploadComponent, ForumChannel, GatewayClient, GatewayError, GatewayErrorCodes, GatewayErrorMessages, GatewayEvents, GatewayRangeError, GatewaySessionStoreError, GatewayTypeError, GroupDMChannel, GroupDMInvite, GroupDMMixin, Guild, GuildAuditLogsEntry, GuildBan, GuildBanManager, GuildChannelFields, GuildChannelManager, GuildChannelMixin, GuildEmoji, GuildEmojiManager, GuildEmojiRoleManager, GuildIntegrationManager, GuildInvite, GuildInviteManager, GuildManager, GuildMember, GuildMemberFlagsBitField, GuildMemberManager, GuildMemberRoleManager, GuildMembersRateLimitError, GuildMembersTimeoutError, GuildOnboarding, GuildOnboardingPrompt, GuildOnboardingPromptOption, GuildPreview, GuildScheduledEvent, GuildScheduledEventManager, GuildSoundboardSoundManager, GuildStickerManager, GuildTemplate, GuildTemplateManager, GuildTemplatesPattern, Integration, IntentsBitField, InteractiveButtonComponent, InviteGuild, InvitesPattern, LabelComponent, LinkButtonComponent, MediaChannel, MediaGalleryComponent, MediaGalleryItem, MentionableSelectMenuComponent, Message, MessageFlagsBitField, MessageManager, MessageMentions, MessagePayload, MessageReaction, Mixin, MultiDispatchAction, MultiDispatchHandlers, NullCache, NumberFlagsBitField, Partials, PermissionOverwriteManager, PermissionOverwrites, PermissionsBitField, Poll, PollAnswer, PremiumButtonComponent, Presence, PresenceManager, PrivateThreadChannel, PublicThreadChannel, RadioGroupComponent, ReactionEmoji, ReactionManager, ReactionUserManager, RegisterAsGatewayListener, RichPresenceAssets, Role, RoleFlagsBitField, RoleManager, RoleSelectMenuComponent, SectionComponent, SeparatorComponent, SoundboardSound, StageChannel, StageInstance, StageInstanceManager, Sticker, StickerPack, StringSelectMenuComponent, Structure, StructureMixin, SystemChannelFlagsBitField, TextChannel, TextChannelMixin, TextDisplayComponent, TextInputComponent, ThreadChannelMemberManager, ThreadChannelMixin, ThreadManager, ThreadMember, ThreadMemberManager, ThreadOnlyChannelMixin, ThumbnailComponent, Typing, UnfurledMediaItem, User, UserFlagsBitField, UserManager, UserSelectMenuComponent, VoiceChannel, VoiceChannelMixin, VoiceState, VoiceStateManager, Webhook, WebhookManager, WebhookMixin, WelcomeScreen, Widget, WidgetMember, basename, bindClient, cleanCodeBlockContent, cleanContent, compareRolePositions, computeChannelPermissions, computeGuildPermissions, computePermissionsIn, computePositions, computeTargetPermissions, createChannel, createComponent, createInvite, discordSort, dispatchPartition, findComponentByCustomId, findName, flatten, getGatewayClient, getSortableGroupTypes, initStructure, isDeepEqual, isThreadChannelType, kClient, kClone, kData, kPatch, kPatchRelations, kRelations, makeError, makePlainError, moveElementInArray, parseEmoji, parseWebhookURL, resolveBase64, resolveCode, resolveColor, resolveFile, resolveGuildTemplateCode, resolveId, resolveImage, resolveImageOption, resolveInviteCode, resolveOverwriteOptions, resolvePartialEmoji, resolveSKUId, snakeCase, snowflakeTimestamp, toAPIOverwrite, toChannelBody, toSnakeCase, transformAPIAuditLogChange, transformAPIAutoModerationAction, transformAPIAutoModerationRuleTriggerMetadata, transformAPIAvatarDecorationData, transformAPIChannelMention, transformAPIEmbedAsset, transformAPIEmbedAuthor, transformAPIEmbedFooter, transformAPIGuildDefaultReaction, transformAPIGuildForumTag, transformAPIGuildScheduledEventEntityMetadata, transformAPIGuildScheduledEventRecurrenceRule, transformAPIIncidentsData, transformAPIMessageActivity, transformAPIMessageCall, transformAPIMessageInteractionMetadata, transformAPIMessageReference, transformAPIRoleSubscriptionData, transformAPIRoleTags, transformAPIUserPrimaryGuild, transformAutoModerationAction, transformAutoModerationRuleTriggerMetadata, transformCollectibles, transformGuildDefaultReaction, transformGuildForumTag, transformGuildScheduledEventRecurrenceRule, transformResolved, verifyString };
15101
15884
  //# sourceMappingURL=index.js.map