1
11import { encodeCursor, parsePagination } from "./pagination.js";
12import type { PrismaService } from "../common/prisma.service.js";
13
14
15export const ACTIVITY_SELECT = {
16 id: true,
17 actorType: true,
18 actorId: true,
19 action: true,
20 resourceType: true,
21 resourceId: true,
22 workspaceId: true,
23 pageId: true,
24 createdAt: true
25} as const;
26
27export type ActivityRow = Record<string, unknown>;
28
29
33export function activityKeyset(cursor: { id: string; position: string }): Record<string, unknown> {
34 return {
35 OR: [
36 { createdAt: { lt: new Date(cursor.position) } },
37 { createdAt: new Date(cursor.position), id: { lt: cursor.id } }
38 ]
39 };
40}
41
42
46export async function pageActivity(
47 prisma: PrismaService,
48 where: Record<string, unknown>,
49 query: { cursor?: string; limit?: string }
50): Promise<{ data: ActivityRow[]; nextCursor: string | null }> {
51 const { cursor, limit } = parsePagination(query);
52 const fullWhere = cursor
53 ? { ...where, AND: activityKeyset(cursor) }
54 : where;
55 const rows = await prisma.auditLog.findMany({
56 where: fullWhere as never,
57 orderBy: [{ createdAt: "desc" }, { id: "desc" }],
58 take: limit + 1,
59 select: ACTIVITY_SELECT
60 });
61 const page = rows.slice(0, limit);
62 const next = rows[limit];
63 return {
64 data: await withActorNames(prisma, page as unknown as ActivityRow[]),
65 nextCursor: next ? encodeCursor(next.id, next.createdAt.toISOString()) : null
66 };
67}
68
69
70export async function withActorNames(
71 prisma: PrismaService,
72 rows: ActivityRow[]
73): Promise<ActivityRow[]> {
74 const ids = [...new Set(rows.filter((r) => r.actorType === "USER").map((r) => r.actorId as string))];
75 if (!ids.length) return rows;
76 const users = await prisma.user.findMany({ where: { id: { in: ids } }, select: { id: true, name: true, displayName: true } });
77 const names = new Map(users.map((u) => [u.id, u.displayName ?? u.name ?? ""]));
78 return rows.map((r) => (r.actorType === "USER" ? { ...r, actorName: names.get(r.actorId as string) ?? null } : r));
79}
80