refactor: unify directory config entry extraction

This commit is contained in:
Peter Steinberger
2026-03-07 19:57:22 +00:00
parent b0ac284dae
commit b9e7521463
6 changed files with 129 additions and 35 deletions

View File

@@ -6,6 +6,8 @@ import {
deleteAccountFromConfigSection,
formatPairingApproveHint,
getChatChannelMeta,
listDirectoryGroupEntriesFromMapKeys,
listDirectoryUserEntriesFromAllowFrom,
migrateBaseNameToDefaultAccount,
missingTargetError,
normalizeAccountId,
@@ -243,34 +245,23 @@ export const googlechatPlugin: ChannelPlugin<ResolvedGoogleChatAccount> = {
cfg: cfg,
accountId,
});
const q = query?.trim().toLowerCase() || "";
const allowFrom = account.config.dm?.allowFrom ?? [];
const peers = Array.from(
new Set(
allowFrom
.map((entry) => String(entry).trim())
.filter((entry) => Boolean(entry) && entry !== "*")
.map((entry) => normalizeGoogleChatTarget(entry) ?? entry),
),
)
.filter((id) => (q ? id.toLowerCase().includes(q) : true))
.slice(0, limit && limit > 0 ? limit : undefined)
.map((id) => ({ kind: "user", id }) as const);
return peers;
return listDirectoryUserEntriesFromAllowFrom({
allowFrom: account.config.dm?.allowFrom,
query,
limit,
normalizeId: (entry) => normalizeGoogleChatTarget(entry) ?? entry,
});
},
listGroups: async ({ cfg, accountId, query, limit }) => {
const account = resolveGoogleChatAccount({
cfg: cfg,
accountId,
});
const groups = account.config.groups ?? {};
const q = query?.trim().toLowerCase() || "";
const entries = Object.keys(groups)
.filter((key) => key && key !== "*")
.filter((key) => (q ? key.toLowerCase().includes(q) : true))
.slice(0, limit && limit > 0 ? limit : undefined)
.map((id) => ({ kind: "group", id }) as const);
return entries;
return listDirectoryGroupEntriesFromMapKeys({
groups: account.config.groups,
query,
limit,
});
},
},
resolver: {

View File

@@ -17,6 +17,7 @@ import {
formatAllowFromLowercase,
formatPairingApproveHint,
migrateBaseNameToDefaultAccount,
listDirectoryUserEntriesFromAllowFrom,
normalizeAccountId,
isNumericTargetId,
PAIRING_APPROVED_MESSAGE,
@@ -196,19 +197,12 @@ export const zaloPlugin: ChannelPlugin<ResolvedZaloAccount> = {
self: async () => null,
listPeers: async ({ cfg, accountId, query, limit }) => {
const account = resolveZaloAccount({ cfg: cfg, accountId });
const q = query?.trim().toLowerCase() || "";
const peers = Array.from(
new Set(
(account.config.allowFrom ?? [])
.map((entry) => String(entry).trim())
.filter((entry) => Boolean(entry) && entry !== "*")
.map((entry) => entry.replace(/^(zalo|zl):/i, "")),
),
)
.filter((id) => (q ? id.toLowerCase().includes(q) : true))
.slice(0, limit && limit > 0 ? limit : undefined)
.map((id) => ({ kind: "user", id }) as const);
return peers;
return listDirectoryUserEntriesFromAllowFrom({
allowFrom: account.config.allowFrom,
query,
limit,
normalizeId: (entry) => entry.replace(/^(zalo|zl):/i, ""),
});
},
listGroups: async () => [],
},

View File

@@ -0,0 +1,39 @@
import { describe, expect, it } from "vitest";
import {
listDirectoryGroupEntriesFromMapKeys,
listDirectoryUserEntriesFromAllowFrom,
} from "./directory-config-helpers.js";
describe("listDirectoryUserEntriesFromAllowFrom", () => {
it("normalizes, deduplicates, filters, and limits user ids", () => {
const entries = listDirectoryUserEntriesFromAllowFrom({
allowFrom: ["", "*", " user:Alice ", "user:alice", "user:Bob", "user:Carla"],
normalizeId: (entry) => entry.replace(/^user:/i, "").toLowerCase(),
query: "a",
limit: 2,
});
expect(entries).toEqual([
{ kind: "user", id: "alice" },
{ kind: "user", id: "carla" },
]);
});
});
describe("listDirectoryGroupEntriesFromMapKeys", () => {
it("extracts normalized group ids from map keys", () => {
const entries = listDirectoryGroupEntriesFromMapKeys({
groups: {
"*": {},
" Space/A ": {},
"space/b": {},
},
normalizeId: (entry) => entry.toLowerCase().replace(/\s+/g, ""),
});
expect(entries).toEqual([
{ kind: "group", id: "space/a" },
{ kind: "group", id: "space/b" },
]);
});
});

View File

@@ -0,0 +1,65 @@
import type { ChannelDirectoryEntry } from "./types.js";
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: { query?: string | null; limit?: number | null },
): 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 function listDirectoryUserEntriesFromAllowFrom(params: {
allowFrom?: readonly unknown[];
query?: string | null;
limit?: number | null;
normalizeId?: (entry: string) => string | null | undefined;
}): ChannelDirectoryEntry[] {
const ids = Array.from(
new Set(
(params.allowFrom ?? [])
.map((entry) => String(entry).trim())
.filter((entry) => Boolean(entry) && entry !== "*")
.map((entry) => {
const normalized = params.normalizeId ? params.normalizeId(entry) : entry;
return typeof normalized === "string" ? normalized.trim() : "";
})
.filter(Boolean),
),
);
return toDirectoryEntries("user", applyDirectoryQueryAndLimit(ids, params));
}
export function listDirectoryGroupEntriesFromMapKeys(params: {
groups?: Record<string, unknown>;
query?: string | null;
limit?: number | null;
normalizeId?: (entry: string) => string | null | undefined;
}): ChannelDirectoryEntry[] {
const ids = Array.from(
new Set(
Object.keys(params.groups ?? {})
.map((entry) => entry.trim())
.filter((entry) => Boolean(entry) && entry !== "*")
.map((entry) => {
const normalized = params.normalizeId ? params.normalizeId(entry) : entry;
return typeof normalized === "string" ? normalized.trim() : "";
})
.filter(Boolean),
),
);
return toDirectoryEntries("group", applyDirectoryQueryAndLimit(ids, params));
}

View File

@@ -14,6 +14,10 @@ export {
deleteAccountFromConfigSection,
setAccountEnabledInConfigSection,
} from "../channels/plugins/config-helpers.js";
export {
listDirectoryGroupEntriesFromMapKeys,
listDirectoryUserEntriesFromAllowFrom,
} from "../channels/plugins/directory-config-helpers.js";
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
export { resolveGoogleChatGroupRequireMention } from "../channels/plugins/group-mentions.js";
export { formatPairingApproveHint } from "../channels/plugins/helpers.js";

View File

@@ -8,6 +8,7 @@ export {
deleteAccountFromConfigSection,
setAccountEnabledInConfigSection,
} from "../channels/plugins/config-helpers.js";
export { listDirectoryUserEntriesFromAllowFrom } from "../channels/plugins/directory-config-helpers.js";
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
export { formatPairingApproveHint } from "../channels/plugins/helpers.js";
export type {