refactor(channels): dedupe directory query/limit pipelines

This commit is contained in:
Peter Steinberger
2026-02-18 16:24:43 +00:00
parent d77dcebcb1
commit 68be4611dd

View File

@@ -34,11 +34,29 @@ function addAllowFromAndDmsIds(
} }
} }
function resolveDirectoryQuery(query?: string | null): string {
return query?.trim().toLowerCase() || "";
}
function resolveDirectoryLimit(limit?: number | null): number | undefined {
return typeof limit === "number" && limit > 0 ? limit : undefined;
}
function applyDirectoryQueryAndLimit(ids: string[], params: DirectoryConfigParams): string[] {
const q = resolveDirectoryQuery(params.query);
const limit = resolveDirectoryLimit(params.limit);
const filtered = ids.filter((id) => (q ? id.toLowerCase().includes(q) : true));
return typeof limit === "number" ? filtered.slice(0, limit) : filtered;
}
function toDirectoryEntries(kind: "user" | "group", ids: string[]): ChannelDirectoryEntry[] {
return ids.map((id) => ({ kind, id }) as const);
}
export async function listSlackDirectoryPeersFromConfig( export async function listSlackDirectoryPeersFromConfig(
params: DirectoryConfigParams, params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> { ): Promise<ChannelDirectoryEntry[]> {
const account = resolveSlackAccount({ cfg: params.cfg, accountId: params.accountId }); const account = resolveSlackAccount({ cfg: params.cfg, accountId: params.accountId });
const q = params.query?.trim().toLowerCase() || "";
const ids = new Set<string>(); const ids = new Set<string>();
addAllowFromAndDmsIds(ids, account.config.allowFrom ?? account.dm?.allowFrom, account.config.dms); addAllowFromAndDmsIds(ids, account.config.allowFrom ?? account.dm?.allowFrom, account.config.dms);
@@ -51,7 +69,7 @@ export async function listSlackDirectoryPeersFromConfig(
} }
} }
return Array.from(ids) const normalizedIds = Array.from(ids)
.map((raw) => raw.trim()) .map((raw) => raw.trim())
.filter(Boolean) .filter(Boolean)
.map((raw) => { .map((raw) => {
@@ -64,32 +82,26 @@ export async function listSlackDirectoryPeersFromConfig(
return normalizeSlackMessagingTarget(target) ?? target.toLowerCase(); return normalizeSlackMessagingTarget(target) ?? target.toLowerCase();
}) })
.filter((id): id is string => Boolean(id)) .filter((id): id is string => Boolean(id))
.filter((id) => id.startsWith("user:")) .filter((id) => id.startsWith("user:"));
.filter((id) => (q ? id.toLowerCase().includes(q) : true)) return toDirectoryEntries("user", applyDirectoryQueryAndLimit(normalizedIds, params));
.slice(0, params.limit && params.limit > 0 ? params.limit : undefined)
.map((id) => ({ kind: "user", id }) as const);
} }
export async function listSlackDirectoryGroupsFromConfig( export async function listSlackDirectoryGroupsFromConfig(
params: DirectoryConfigParams, params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> { ): Promise<ChannelDirectoryEntry[]> {
const account = resolveSlackAccount({ cfg: params.cfg, accountId: params.accountId }); const account = resolveSlackAccount({ cfg: params.cfg, accountId: params.accountId });
const q = params.query?.trim().toLowerCase() || ""; const ids = Object.keys(account.config.channels ?? {})
return Object.keys(account.config.channels ?? {})
.map((raw) => raw.trim()) .map((raw) => raw.trim())
.filter(Boolean) .filter(Boolean)
.map((raw) => normalizeSlackMessagingTarget(raw) ?? raw.toLowerCase()) .map((raw) => normalizeSlackMessagingTarget(raw) ?? raw.toLowerCase())
.filter((id) => id.startsWith("channel:")) .filter((id) => id.startsWith("channel:"));
.filter((id) => (q ? id.toLowerCase().includes(q) : true)) return toDirectoryEntries("group", applyDirectoryQueryAndLimit(ids, params));
.slice(0, params.limit && params.limit > 0 ? params.limit : undefined)
.map((id) => ({ kind: "group", id }) as const);
} }
export async function listDiscordDirectoryPeersFromConfig( export async function listDiscordDirectoryPeersFromConfig(
params: DirectoryConfigParams, params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> { ): Promise<ChannelDirectoryEntry[]> {
const account = resolveDiscordAccount({ cfg: params.cfg, accountId: params.accountId }); const account = resolveDiscordAccount({ cfg: params.cfg, accountId: params.accountId });
const q = params.query?.trim().toLowerCase() || "";
const ids = new Set<string>(); const ids = new Set<string>();
addAllowFromAndDmsIds( addAllowFromAndDmsIds(
@@ -114,7 +126,7 @@ export async function listDiscordDirectoryPeersFromConfig(
} }
} }
return Array.from(ids) const normalizedIds = Array.from(ids)
.map((raw) => raw.trim()) .map((raw) => raw.trim())
.filter(Boolean) .filter(Boolean)
.map((raw) => { .map((raw) => {
@@ -125,17 +137,14 @@ export async function listDiscordDirectoryPeersFromConfig(
} }
return `user:${cleaned}`; return `user:${cleaned}`;
}) })
.filter((id): id is string => Boolean(id)) .filter((id): id is string => Boolean(id));
.filter((id) => (q ? id.toLowerCase().includes(q) : true)) return toDirectoryEntries("user", applyDirectoryQueryAndLimit(normalizedIds, params));
.slice(0, params.limit && params.limit > 0 ? params.limit : undefined)
.map((id) => ({ kind: "user", id }) as const);
} }
export async function listDiscordDirectoryGroupsFromConfig( export async function listDiscordDirectoryGroupsFromConfig(
params: DirectoryConfigParams, params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> { ): Promise<ChannelDirectoryEntry[]> {
const account = resolveDiscordAccount({ cfg: params.cfg, accountId: params.accountId }); const account = resolveDiscordAccount({ cfg: params.cfg, accountId: params.accountId });
const q = params.query?.trim().toLowerCase() || "";
const ids = new Set<string>(); const ids = new Set<string>();
for (const guild of Object.values(account.config.guilds ?? {})) { for (const guild of Object.values(account.config.guilds ?? {})) {
for (const channelId of Object.keys(guild.channels ?? {})) { for (const channelId of Object.keys(guild.channels ?? {})) {
@@ -146,7 +155,7 @@ export async function listDiscordDirectoryGroupsFromConfig(
} }
} }
return Array.from(ids) const normalizedIds = Array.from(ids)
.map((raw) => raw.trim()) .map((raw) => raw.trim())
.filter(Boolean) .filter(Boolean)
.map((raw) => { .map((raw) => {
@@ -157,22 +166,19 @@ export async function listDiscordDirectoryGroupsFromConfig(
} }
return `channel:${cleaned}`; return `channel:${cleaned}`;
}) })
.filter((id): id is string => Boolean(id)) .filter((id): id is string => Boolean(id));
.filter((id) => (q ? id.toLowerCase().includes(q) : true)) return toDirectoryEntries("group", applyDirectoryQueryAndLimit(normalizedIds, params));
.slice(0, params.limit && params.limit > 0 ? params.limit : undefined)
.map((id) => ({ kind: "group", id }) as const);
} }
export async function listTelegramDirectoryPeersFromConfig( export async function listTelegramDirectoryPeersFromConfig(
params: DirectoryConfigParams, params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> { ): Promise<ChannelDirectoryEntry[]> {
const account = resolveTelegramAccount({ cfg: params.cfg, accountId: params.accountId }); const account = resolveTelegramAccount({ cfg: params.cfg, accountId: params.accountId });
const q = params.query?.trim().toLowerCase() || "";
const raw = [ const raw = [
...(account.config.allowFrom ?? []).map((entry) => String(entry)), ...(account.config.allowFrom ?? []).map((entry) => String(entry)),
...Object.keys(account.config.dms ?? {}), ...Object.keys(account.config.dms ?? {}),
]; ];
return Array.from( const ids = Array.from(
new Set( new Set(
raw raw
.map((entry) => entry.trim()) .map((entry) => entry.trim())
@@ -191,50 +197,39 @@ export async function listTelegramDirectoryPeersFromConfig(
const withAt = trimmed.startsWith("@") ? trimmed : `@${trimmed}`; const withAt = trimmed.startsWith("@") ? trimmed : `@${trimmed}`;
return withAt; return withAt;
}) })
.filter((id): id is string => Boolean(id)) .filter((id): id is string => Boolean(id));
.filter((id) => (q ? id.toLowerCase().includes(q) : true)) return toDirectoryEntries("user", applyDirectoryQueryAndLimit(ids, params));
.slice(0, params.limit && params.limit > 0 ? params.limit : undefined)
.map((id) => ({ kind: "user", id }) as const);
} }
export async function listTelegramDirectoryGroupsFromConfig( export async function listTelegramDirectoryGroupsFromConfig(
params: DirectoryConfigParams, params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> { ): Promise<ChannelDirectoryEntry[]> {
const account = resolveTelegramAccount({ cfg: params.cfg, accountId: params.accountId }); const account = resolveTelegramAccount({ cfg: params.cfg, accountId: params.accountId });
const q = params.query?.trim().toLowerCase() || ""; const ids = Object.keys(account.config.groups ?? {})
return Object.keys(account.config.groups ?? {})
.map((id) => id.trim()) .map((id) => id.trim())
.filter((id) => Boolean(id) && id !== "*") .filter((id) => Boolean(id) && id !== "*");
.filter((id) => (q ? id.toLowerCase().includes(q) : true)) return toDirectoryEntries("group", applyDirectoryQueryAndLimit(ids, params));
.slice(0, params.limit && params.limit > 0 ? params.limit : undefined)
.map((id) => ({ kind: "group", id }) as const);
} }
export async function listWhatsAppDirectoryPeersFromConfig( export async function listWhatsAppDirectoryPeersFromConfig(
params: DirectoryConfigParams, params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> { ): Promise<ChannelDirectoryEntry[]> {
const account = resolveWhatsAppAccount({ cfg: params.cfg, accountId: params.accountId }); const account = resolveWhatsAppAccount({ cfg: params.cfg, accountId: params.accountId });
const q = params.query?.trim().toLowerCase() || ""; const ids = (account.allowFrom ?? [])
return (account.allowFrom ?? [])
.map((entry) => String(entry).trim()) .map((entry) => String(entry).trim())
.filter((entry) => Boolean(entry) && entry !== "*") .filter((entry) => Boolean(entry) && entry !== "*")
.map((entry) => normalizeWhatsAppTarget(entry) ?? "") .map((entry) => normalizeWhatsAppTarget(entry) ?? "")
.filter(Boolean) .filter(Boolean)
.filter((id) => !isWhatsAppGroupJid(id)) .filter((id) => !isWhatsAppGroupJid(id));
.filter((id) => (q ? id.toLowerCase().includes(q) : true)) return toDirectoryEntries("user", applyDirectoryQueryAndLimit(ids, params));
.slice(0, params.limit && params.limit > 0 ? params.limit : undefined)
.map((id) => ({ kind: "user", id }) as const);
} }
export async function listWhatsAppDirectoryGroupsFromConfig( export async function listWhatsAppDirectoryGroupsFromConfig(
params: DirectoryConfigParams, params: DirectoryConfigParams,
): Promise<ChannelDirectoryEntry[]> { ): Promise<ChannelDirectoryEntry[]> {
const account = resolveWhatsAppAccount({ cfg: params.cfg, accountId: params.accountId }); const account = resolveWhatsAppAccount({ cfg: params.cfg, accountId: params.accountId });
const q = params.query?.trim().toLowerCase() || ""; const ids = Object.keys(account.groups ?? {})
return Object.keys(account.groups ?? {})
.map((id) => id.trim()) .map((id) => id.trim())
.filter((id) => Boolean(id) && id !== "*") .filter((id) => Boolean(id) && id !== "*");
.filter((id) => (q ? id.toLowerCase().includes(q) : true)) return toDirectoryEntries("group", applyDirectoryQueryAndLimit(ids, params));
.slice(0, params.limit && params.limit > 0 ? params.limit : undefined)
.map((id) => ({ kind: "group", id }) as const);
} }