fix(discord): invalidate member cache on lifecycle events (#110414)

Clear cached member and user entities when members join or leave, matching the existing update-event behavior and preventing stale role authorization.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
zhanxingxin1998
2026-08-05 13:14:42 +08:00
committed by GitHub
parent 141a16f7b3
commit 353b4a339a
2 changed files with 25 additions and 1 deletions
@@ -93,3 +93,25 @@ describe("DiscordEntityCache eviction", () => {
expect(getCalls()).toBe(2);
});
});
describe("DiscordEntityCache gateway invalidation", () => {
it.each([
GatewayDispatchEvents.GuildMemberAdd,
GatewayDispatchEvents.GuildMemberRemove,
GatewayDispatchEvents.GuildMemberUpdate,
])("invalidates member and user entries for %s", async (event) => {
const { cache, getCalls } = makeCache({ ttlMs: 60_000 });
await cache.fetchMember("g1", "u1");
await cache.fetchUser("u1");
await cache.fetchMember("g1", "u1");
await cache.fetchUser("u1");
expect(getCalls()).toBe(2);
cache.invalidateForGatewayEvent(event, { guild_id: "g1", user: { id: "u1" } });
await cache.fetchMember("g1", "u1");
await cache.fetchUser("u1");
expect(getCalls()).toBe(4);
});
});
@@ -70,6 +70,8 @@ export class DiscordEntityCache {
const threadUpdate: string = GatewayDispatchEvents.ThreadUpdate;
const threadDelete: string = GatewayDispatchEvents.ThreadDelete;
const guildUpdate: string = GatewayDispatchEvents.GuildUpdate;
const guildMemberAdd: string = GatewayDispatchEvents.GuildMemberAdd;
const guildMemberRemove: string = GatewayDispatchEvents.GuildMemberRemove;
const guildMemberUpdate: string = GatewayDispatchEvents.GuildMemberUpdate;
if (
type === channelUpdate ||
@@ -82,7 +84,7 @@ export class DiscordEntityCache {
if (type === guildUpdate) {
this.deleteId("guild", raw.id);
}
if (type === guildMemberUpdate) {
if (type === guildMemberAdd || type === guildMemberRemove || type === guildMemberUpdate) {
const guildId = raw.guild_id;
const user = raw.user && typeof raw.user === "object" ? (raw.user as { id?: unknown }) : {};
if (typeof guildId === "string" && typeof user.id === "string") {