From 25be51967a7e1ff92e83fb8cd420a344be690870 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 15 Feb 2026 17:26:27 +0000 Subject: [PATCH] refactor(channels): share allowlist resolution summary --- src/channels/allowlists/resolve-utils.test.ts | 25 +++++++++++++++++++ src/channels/allowlists/resolve-utils.ts | 18 +++++++++---- src/discord/monitor/provider.ts | 12 +-------- src/slack/monitor/provider.ts | 23 ++++++++--------- 4 files changed, 50 insertions(+), 28 deletions(-) create mode 100644 src/channels/allowlists/resolve-utils.test.ts diff --git a/src/channels/allowlists/resolve-utils.test.ts b/src/channels/allowlists/resolve-utils.test.ts new file mode 100644 index 00000000000..496ac7a224f --- /dev/null +++ b/src/channels/allowlists/resolve-utils.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it } from "vitest"; +import { buildAllowlistResolutionSummary } from "./resolve-utils.js"; + +describe("buildAllowlistResolutionSummary", () => { + it("returns mapping, additions, and unresolved (including missing ids)", () => { + const resolvedUsers = [ + { input: "a", resolved: true, id: "1" }, + { input: "b", resolved: false }, + { input: "c", resolved: true }, + ]; + const result = buildAllowlistResolutionSummary(resolvedUsers); + expect(result.mapping).toEqual(["a→1"]); + expect(result.additions).toEqual(["1"]); + expect(result.unresolved).toEqual(["b", "c"]); + }); + + it("supports custom resolved formatting", () => { + const resolvedUsers = [{ input: "a", resolved: true, id: "1", note: "x" }]; + const result = buildAllowlistResolutionSummary(resolvedUsers, { + formatResolved: (entry) => + `${entry.input}→${entry.id}${(entry as { note?: string }).note ? " (note)" : ""}`, + }); + expect(result.mapping).toEqual(["a→1 (note)"]); + }); +}); diff --git a/src/channels/allowlists/resolve-utils.ts b/src/channels/allowlists/resolve-utils.ts index a4a747f77dd..054b9cdfdda 100644 --- a/src/channels/allowlists/resolve-utils.ts +++ b/src/channels/allowlists/resolve-utils.ts @@ -35,17 +35,25 @@ export function mergeAllowlist(params: { export function buildAllowlistResolutionSummary( resolvedUsers: T[], + opts?: { formatResolved?: (entry: T) => string }, ): { resolvedMap: Map; mapping: string[]; unresolved: string[]; + additions: string[]; } { const resolvedMap = new Map(resolvedUsers.map((entry) => [entry.input, entry])); - const mapping = resolvedUsers - .filter((entry) => entry.resolved && entry.id) - .map((entry) => `${entry.input}→${entry.id}`); - const unresolved = resolvedUsers.filter((entry) => !entry.resolved).map((entry) => entry.input); - return { resolvedMap, mapping, unresolved }; + const resolvedOk = (entry: T) => Boolean(entry.resolved && entry.id); + const formatResolved = opts?.formatResolved ?? ((entry: T) => `${entry.input}→${entry.id}`); + const mapping = resolvedUsers.filter(resolvedOk).map(formatResolved); + const additions = resolvedUsers + .filter(resolvedOk) + .map((entry) => entry.id) + .filter((entry): entry is string => Boolean(entry)); + const unresolved = resolvedUsers + .filter((entry) => !resolvedOk(entry)) + .map((entry) => entry.input); + return { resolvedMap, mapping, unresolved, additions }; } export function resolveAllowlistIdAdditions(params: { diff --git a/src/discord/monitor/provider.ts b/src/discord/monitor/provider.ts index a52f8c911cb..f90d11de335 100644 --- a/src/discord/monitor/provider.ts +++ b/src/discord/monitor/provider.ts @@ -278,17 +278,7 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) { token, entries: allowEntries.map((entry) => String(entry)), }); - const mapping: string[] = []; - const unresolved: string[] = []; - const additions: string[] = []; - for (const entry of resolvedUsers) { - if (entry.resolved && entry.id) { - mapping.push(`${entry.input}→${entry.id}`); - additions.push(entry.id); - } else { - unresolved.push(entry.input); - } - } + const { mapping, unresolved, additions } = buildAllowlistResolutionSummary(resolvedUsers); allowFrom = mergeAllowlist({ existing: allowFrom, additions }); summarizeMapping("discord users", mapping, unresolved, runtime); } catch (err) { diff --git a/src/slack/monitor/provider.ts b/src/slack/monitor/provider.ts index a5c3a38b22f..9a15e87e765 100644 --- a/src/slack/monitor/provider.ts +++ b/src/slack/monitor/provider.ts @@ -283,18 +283,17 @@ export async function monitorSlackProvider(opts: MonitorSlackOpts = {}) { token: resolveToken, entries: allowEntries.map((entry) => String(entry)), }); - const mapping: string[] = []; - const unresolved: string[] = []; - const additions: string[] = []; - for (const entry of resolvedUsers) { - if (entry.resolved && entry.id) { - const note = entry.note ? ` (${entry.note})` : ""; - mapping.push(`${entry.input}→${entry.id}${note}`); - additions.push(entry.id); - } else { - unresolved.push(entry.input); - } - } + const { mapping, unresolved, additions } = buildAllowlistResolutionSummary( + resolvedUsers, + { + formatResolved: (entry) => { + const note = (entry as { note?: string }).note + ? ` (${(entry as { note?: string }).note})` + : ""; + return `${entry.input}→${entry.id}${note}`; + }, + }, + ); allowFrom = mergeAllowlist({ existing: allowFrom, additions }); ctx.allowFrom = normalizeAllowList(allowFrom); summarizeMapping("slack users", mapping, unresolved, runtime);