diff --git a/src/discord/monitor/listeners.ts b/src/discord/monitor/listeners.ts index f3bcee77f..20cc76aa3 100644 --- a/src/discord/monitor/listeners.ts +++ b/src/discord/monitor/listeners.ts @@ -5,6 +5,7 @@ import { MessageReactionAddListener, MessageReactionRemoveListener, PresenceUpdateListener, + type User, } from "@buape/carbon"; import { danger } from "../../globals.js"; import { formatDurationSeconds } from "../../infra/format-time/format-duration.ts"; @@ -262,6 +263,44 @@ async function handleDiscordReactionEvent(params: { contextKey, }); }; + const shouldNotifyReaction = (options: { + mode: "off" | "own" | "all" | "allowlist"; + messageAuthorId?: string; + }) => + shouldEmitDiscordReactionNotification({ + mode: options.mode, + botId: botUserId, + messageAuthorId: options.messageAuthorId, + userId: user.id, + userName: user.username, + userTag: formatDiscordUserTag(user), + allowlist: guildInfo?.users, + }); + const emitReactionWithAuthor = (message: { author?: User } | null) => { + const { baseText } = resolveReactionBase(); + const authorLabel = message?.author ? formatDiscordUserTag(message.author) : undefined; + const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText; + emitReaction(text, parentId); + }; + const loadThreadParentInfo = async () => { + if (!parentId) { + return; + } + const parentInfo = await resolveDiscordChannelInfo(client, parentId); + parentName = parentInfo?.name; + parentSlug = parentName ? normalizeDiscordSlug(parentName) : ""; + }; + const resolveThreadChannelConfig = () => + resolveDiscordChannelConfigWithFallback({ + guildInfo, + channelId: data.channel_id, + channelName, + channelSlug, + parentId, + parentName, + parentSlug, + scope: "thread", + }); // Parallelize async operations for thread channels if (isThreadChannel) { @@ -280,38 +319,16 @@ async function handleDiscordReactionEvent(params: { if (reactionMode === "all" || reactionMode === "allowlist") { const channelInfo = await channelInfoPromise; parentId = channelInfo?.parentId; + await loadThreadParentInfo(); - if (parentId) { - const parentInfo = await resolveDiscordChannelInfo(client, parentId); - parentName = parentInfo?.name; - parentSlug = parentName ? normalizeDiscordSlug(parentName) : ""; - } - - const channelConfig = resolveDiscordChannelConfigWithFallback({ - guildInfo, - channelId: data.channel_id, - channelName, - channelSlug, - parentId, - parentName, - parentSlug, - scope: "thread", - }); + const channelConfig = resolveThreadChannelConfig(); if (channelConfig?.allowed === false) { return; } // For allowlist mode, check if user is in allowlist first if (reactionMode === "allowlist") { - const shouldNotifyAllowlist = shouldEmitDiscordReactionNotification({ - mode: reactionMode, - botId: botUserId, - userId: user.id, - userName: user.username, - userTag: formatDiscordUserTag(user), - allowlist: guildInfo?.users, - }); - if (!shouldNotifyAllowlist) { + if (!shouldNotifyReaction({ mode: reactionMode })) { return; } } @@ -326,45 +343,19 @@ async function handleDiscordReactionEvent(params: { const [channelInfo, message] = await Promise.all([channelInfoPromise, messagePromise]); parentId = channelInfo?.parentId; + await loadThreadParentInfo(); - if (parentId) { - const parentInfo = await resolveDiscordChannelInfo(client, parentId); - parentName = parentInfo?.name; - parentSlug = parentName ? normalizeDiscordSlug(parentName) : ""; - } - - const channelConfig = resolveDiscordChannelConfigWithFallback({ - guildInfo, - channelId: data.channel_id, - channelName, - channelSlug, - parentId, - parentName, - parentSlug, - scope: "thread", - }); + const channelConfig = resolveThreadChannelConfig(); if (channelConfig?.allowed === false) { return; } const messageAuthorId = message?.author?.id ?? undefined; - const shouldNotify = shouldEmitDiscordReactionNotification({ - mode: reactionMode, - botId: botUserId, - messageAuthorId, - userId: user.id, - userName: user.username, - userTag: formatDiscordUserTag(user), - allowlist: guildInfo?.users, - }); - if (!shouldNotify) { + if (!shouldNotifyReaction({ mode: reactionMode, messageAuthorId })) { return; } - const { baseText } = resolveReactionBase(); - const authorLabel = message?.author ? formatDiscordUserTag(message.author) : undefined; - const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText; - emitReaction(text, parentId); + emitReactionWithAuthor(message); return; } @@ -394,15 +385,7 @@ async function handleDiscordReactionEvent(params: { if (reactionMode === "all" || reactionMode === "allowlist") { // For allowlist mode, check if user is in allowlist first if (reactionMode === "allowlist") { - const shouldNotifyAllowlist = shouldEmitDiscordReactionNotification({ - mode: reactionMode, - botId: botUserId, - userId: user.id, - userName: user.username, - userTag: formatDiscordUserTag(user), - allowlist: guildInfo?.users, - }); - if (!shouldNotifyAllowlist) { + if (!shouldNotifyReaction({ mode: reactionMode })) { return; } } @@ -415,23 +398,11 @@ async function handleDiscordReactionEvent(params: { // For "own" mode, we need to fetch the message to check the author const message = await data.message.fetch().catch(() => null); const messageAuthorId = message?.author?.id ?? undefined; - const shouldNotify = shouldEmitDiscordReactionNotification({ - mode: reactionMode, - botId: botUserId, - messageAuthorId, - userId: user.id, - userName: user.username, - userTag: formatDiscordUserTag(user), - allowlist: guildInfo?.users, - }); - if (!shouldNotify) { + if (!shouldNotifyReaction({ mode: reactionMode, messageAuthorId })) { return; } - const { baseText } = resolveReactionBase(); - const authorLabel = message?.author ? formatDiscordUserTag(message.author) : undefined; - const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText; - emitReaction(text, parentId); + emitReactionWithAuthor(message); } catch (err) { params.logger.error(danger(`discord reaction handler failed: ${String(err)}`)); }