import type { AuthSession } from "@/lib/auth/session"; import { hasSuperAdminAccess } from "@/lib/auth/permissions"; import { getOrganizationApiConfig, listOrganizations, type OrganizationInfo } from "@/lib/server/organization-client"; import type { UsageContext } from "@/lib/types"; const ORGANIZATION_CACHE_MS = 5 * 60 * 1000; const organizationCache = new Map(); export async function resolvePlatformUsageContext(session: AuthSession): Promise { const { user } = session; const context: UsageContext = { source: "platform", accountId: user.id, username: user.username, displayName: user.displayName, role: hasSuperAdminAccess(user) ? "super_admin" : user.role, tenantId: user.tenantId, organizationId: user.organizationId, organizationName: user.organizationName }; if (user.organizationId) return context; if (!user.tenantId) return context; const cached = organizationCache.get(user.tenantId); if (cached && cached.expiresAt > Date.now()) { return { ...context, organizationId: cached.organizationId, organizationName: cached.organizationName }; } const config = getOrganizationApiConfig(session.accessToken); if (config.defaultOrganizationId && config.tenantId === user.tenantId) { cacheOrganization(user.tenantId, { organizationId: config.defaultOrganizationId }); return { ...context, organizationId: config.defaultOrganizationId }; } const organization = await findOrganizationForTenant(user.tenantId, session.accessToken); if (!organization) return context; cacheOrganization(user.tenantId, organization); return { ...context, organizationId: organization.organizationId, organizationName: organization.organizationName }; } export function clearUsageOrganizationCacheForTests() { organizationCache.clear(); } async function findOrganizationForTenant(tenantId: string, accessToken?: string): Promise { const contexts = accessToken ? [{ accessToken }, {}] : [{}]; for (const context of contexts) { try { const organizations = await listOrganizations(context); const match = organizations.find((item) => String(item.organizationBindTenantId ?? "") === tenantId); if (match) return match; } catch { // Organization lookup must never block a generation request. Missing matches remain unassigned. } } return null; } function cacheOrganization(tenantId: string, organization: { organizationId: string; organizationName?: string }) { organizationCache.set(tenantId, { expiresAt: Date.now() + ORGANIZATION_CACHE_MS, organizationId: organization.organizationId, organizationName: organization.organizationName }); }