refactor(channels): share channel config matching

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Peter Steinberger
2026-01-17 22:30:37 +00:00
parent 277e43e32c
commit e63e483c38
7 changed files with 137 additions and 39 deletions

View File

@@ -1,5 +1,6 @@
import type { Guild, User } from "@buape/carbon";
import { buildChannelKeyCandidates, resolveChannelEntryMatch } from "../../channels/channel-config.js";
import { formatDiscordUserTag } from "./format.js";
export type DiscordAllowList = {
@@ -138,17 +139,25 @@ export function resolveDiscordGuildEntry(params: {
}
type DiscordChannelEntry = NonNullable<DiscordGuildEntryResolved["channels"]>[string];
type DiscordChannelLookup = {
id: string;
name?: string;
slug?: string;
};
type DiscordChannelScope = "channel" | "thread";
function resolveDiscordChannelEntry(
channels: NonNullable<DiscordGuildEntryResolved["channels"]>,
channelId: string,
channelName?: string,
channelSlug?: string,
params: DiscordChannelLookup & { allowNameMatch?: boolean },
): DiscordChannelEntry | null {
if (channelId && channels[channelId]) return channels[channelId];
if (channelSlug && channels[channelSlug]) return channels[channelSlug];
if (channelName && channels[channelName]) return channels[channelName];
return null;
const allowNameMatch = params.allowNameMatch !== false;
const keys = buildChannelKeyCandidates(
params.id,
allowNameMatch ? params.slug : undefined,
allowNameMatch ? params.name : undefined,
);
const { entry } = resolveChannelEntryMatch({ entries: channels, keys });
return entry ?? null;
}
function resolveDiscordChannelConfigEntry(
@@ -174,7 +183,11 @@ export function resolveDiscordChannelConfig(params: {
const { guildInfo, channelId, channelName, channelSlug } = params;
const channels = guildInfo?.channels;
if (!channels) return null;
const entry = resolveDiscordChannelEntry(channels, channelId, channelName, channelSlug);
const entry = resolveDiscordChannelEntry(channels, {
id: channelId,
name: channelName,
slug: channelSlug,
});
if (!entry) return { allowed: false };
return resolveDiscordChannelConfigEntry(entry);
}
@@ -187,21 +200,34 @@ export function resolveDiscordChannelConfigWithFallback(params: {
parentId?: string;
parentName?: string;
parentSlug?: string;
scope?: DiscordChannelScope;
}): DiscordChannelConfigResolved | null {
const { guildInfo, channelId, channelName, channelSlug, parentId, parentName, parentSlug } =
params;
const {
guildInfo,
channelId,
channelName,
channelSlug,
parentId,
parentName,
parentSlug,
scope,
} = params;
const channels = guildInfo?.channels;
if (!channels) return null;
const entry = resolveDiscordChannelEntry(channels, channelId, channelName, channelSlug);
const entry = resolveDiscordChannelEntry(channels, {
id: channelId,
name: channelName,
slug: channelSlug,
allowNameMatch: scope !== "thread",
});
if (entry) return resolveDiscordChannelConfigEntry(entry);
if (parentId || parentName || parentSlug) {
const resolvedParentSlug = parentSlug ?? (parentName ? normalizeDiscordSlug(parentName) : "");
const parentEntry = resolveDiscordChannelEntry(
channels,
parentId ?? "",
parentName,
resolvedParentSlug,
);
const parentEntry = resolveDiscordChannelEntry(channels, {
id: parentId ?? "",
name: parentName,
slug: resolvedParentSlug,
});
if (parentEntry) return resolveDiscordChannelConfigEntry(parentEntry);
}
return { allowed: false };

View File

@@ -249,6 +249,7 @@ export async function preflightDiscordMessage(
parentId: threadParentId ?? undefined,
parentName: threadParentName ?? undefined,
parentSlug: threadParentSlug,
scope: threadChannel ? "thread" : "channel",
})
: null;
if (isGuildMessage && channelConfig?.enabled === false) {

View File

@@ -553,6 +553,7 @@ async function dispatchDiscordCommandInteraction(params: {
parentId: threadParentId,
parentName: threadParentName,
parentSlug: threadParentSlug,
scope: isThreadChannel ? "thread" : "channel",
})
: null;
if (channelConfig?.enabled === false) {