export async function introspectGuildToken(token: string): Promise<{ active: boolean; user?: { id: string; email?: string } }> { const centerBaseUrl = process.env.FABRIC_BACKEND_GUILD_CENTER_BASE_URL; const guildNodeId = process.env.FABRIC_BACKEND_GUILD_NODE_ID; const centerApiKey = process.env.FABRIC_BACKEND_GUILD_CENTER_API_KEY; if (!centerBaseUrl || !guildNodeId || !centerApiKey) { return { active: false }; } const res = await fetch(`${centerBaseUrl}/api/auth/introspect`, { method: 'POST', headers: { 'content-type': 'application/json', 'x-api-key': centerApiKey, }, body: JSON.stringify({ token, guildNodeId }), }); if (!res.ok) return { active: false }; const data = (await res.json()) as { active?: boolean; user?: { id: string; email?: string } }; if (!data.active) return { active: false }; return { active: true, user: data.user, }; } /** * Fetch the single Center-scoped admin user (if any). * Same x-api-key auth as introspect / resolve-names. * Returns `null` when no admin is set OR the request fails (treated * identically — the guild simply falls back to "no admin observer"). */ export async function fetchAdminEmail(): Promise<{ email: string; userId: string } | null> { const centerBaseUrl = process.env.FABRIC_BACKEND_GUILD_CENTER_BASE_URL; const centerApiKey = process.env.FABRIC_BACKEND_GUILD_CENTER_API_KEY; if (!centerBaseUrl || !centerApiKey) return null; try { const res = await fetch(`${centerBaseUrl}/api/auth/admin-email`, { method: 'GET', headers: { 'x-api-key': centerApiKey }, }); if (!res.ok) return null; const data = (await res.json()) as { email?: string; userId?: string } | null; if (!data || !data.email || !data.userId) return null; return { email: data.email, userId: data.userId }; } catch { return null; } } // Resolve <@user.name:NAME> names to userIds within this guild node via // Center. Unresolved names are simply absent from the returned map. export async function resolveUserNames(names: string[]): Promise> { const centerBaseUrl = process.env.FABRIC_BACKEND_GUILD_CENTER_BASE_URL; const guildNodeId = process.env.FABRIC_BACKEND_GUILD_NODE_ID; const centerApiKey = process.env.FABRIC_BACKEND_GUILD_CENTER_API_KEY; if (!centerBaseUrl || !guildNodeId || !centerApiKey || !names.length) return {}; try { const res = await fetch(`${centerBaseUrl}/api/auth/resolve-names`, { method: 'POST', headers: { 'content-type': 'application/json', 'x-api-key': centerApiKey }, body: JSON.stringify({ guildNodeId, names }), }); if (!res.ok) return {}; const data = (await res.json()) as { resolved?: Record }; return data.resolved ?? {}; } catch { return {}; } }