import { inArray } from 'drizzle-orm'; import { db } from '@/lib/db'; import { user } from '@/lib/db/schema/users'; import { searchAuditLogs } from '@/lib/services/audit-search.service'; /** * Shared loader for the per-entity Activity tab. Wraps `searchAuditLogs` * with actor-email resolution so each row can render `who did what`. * * Tenant gate happens at the API route — this service trusts the caller * to pass an entityId that belongs to `portId`. */ export async function loadEntityActivity(args: { portId: string; entityType: string; entityId: string; limit?: number; }) { const { rows } = await searchAuditLogs({ portId: args.portId, entityType: args.entityType, entityId: args.entityId, limit: args.limit ?? 50, }); const userIds = Array.from( new Set(rows.map((r) => r.userId).filter((u): u is string => Boolean(u))), ); const userRows = userIds.length ? await db .select({ id: user.id, email: user.email, name: user.name }) .from(user) .where(inArray(user.id, userIds)) : []; const userMap = new Map(userRows.map((u) => [u.id, u])); return rows.map((r) => ({ ...r, actor: r.userId ? (userMap.get(r.userId) ?? null) : null, })); }