import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/routing"; const DISCORD_DIRECTORY_CACHE_MAX_ENTRIES = 4000; const DISCORD_DISCRIMINATOR_SUFFIX = /#\d{4}$/; const DIRECTORY_HANDLE_CACHE = new Map>(); function normalizeAccountCacheKey(accountId?: string | null): string { const normalized = normalizeAccountId(accountId ?? DEFAULT_ACCOUNT_ID); return normalized || DEFAULT_ACCOUNT_ID; } function normalizeSnowflake(value: string | number | bigint): string | null { const text = String(value ?? "").trim(); if (!/^\d+$/.test(text)) { return null; } return text; } function normalizeHandleKey(raw: string): string | null { let handle = raw.trim(); if (!handle) { return null; } if (handle.startsWith("@")) { handle = handle.slice(1).trim(); } if (!handle || /\s/.test(handle)) { return null; } return handle.toLowerCase(); } function ensureAccountCache(accountId?: string | null): Map { const cacheKey = normalizeAccountCacheKey(accountId); const existing = DIRECTORY_HANDLE_CACHE.get(cacheKey); if (existing) { return existing; } const created = new Map(); DIRECTORY_HANDLE_CACHE.set(cacheKey, created); return created; } function setCacheEntry(cache: Map, key: string, userId: string): void { if (cache.has(key)) { cache.delete(key); } cache.set(key, userId); if (cache.size <= DISCORD_DIRECTORY_CACHE_MAX_ENTRIES) { return; } const oldest = cache.keys().next(); if (!oldest.done) { cache.delete(oldest.value); } } export function rememberDiscordDirectoryUser(params: { accountId?: string | null; userId: string | number | bigint; handles: Array; }): void { const userId = normalizeSnowflake(params.userId); if (!userId) { return; } const cache = ensureAccountCache(params.accountId); for (const candidate of params.handles) { if (typeof candidate !== "string") { continue; } const handle = normalizeHandleKey(candidate); if (!handle) { continue; } setCacheEntry(cache, handle, userId); const withoutDiscriminator = handle.replace(DISCORD_DISCRIMINATOR_SUFFIX, ""); if (withoutDiscriminator && withoutDiscriminator !== handle) { setCacheEntry(cache, withoutDiscriminator, userId); } } } export function resolveDiscordDirectoryUserId(params: { accountId?: string | null; handle: string; }): string | undefined { const cache = DIRECTORY_HANDLE_CACHE.get(normalizeAccountCacheKey(params.accountId)); if (!cache) { return undefined; } const handle = normalizeHandleKey(params.handle); if (!handle) { return undefined; } const direct = cache.get(handle); if (direct) { return direct; } const withoutDiscriminator = handle.replace(DISCORD_DISCRIMINATOR_SUFFIX, ""); if (!withoutDiscriminator || withoutDiscriminator === handle) { return undefined; } return cache.get(withoutDiscriminator); } export function __resetDiscordDirectoryCacheForTest(): void { DIRECTORY_HANDLE_CACHE.clear(); }