import { createTRPCContext, loadRoleDefaults } from "@capakraken/api"; import { appRouter } from "@capakraken/api/router"; import { prisma } from "@capakraken/db"; import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; import type { NextRequest } from "next/server"; import { auth } from "~/server/auth.js"; // Throttle lastActiveAt updates: max once per 60s per user const lastActiveCache = new Map(); const ACTIVITY_THROTTLE_MS = 60_000; function trackActivity(userId: string) { const now = Date.now(); const last = lastActiveCache.get(userId) ?? 0; if (now - last < ACTIVITY_THROTTLE_MS) return; lastActiveCache.set(userId, now); prisma.user.update({ where: { id: userId }, data: { lastActiveAt: new Date(now) }, }).catch(() => {/* ignore */}); } const handler = async (req: NextRequest) => { const session = await auth(); const dbUser = session?.user?.email ? await prisma.user.findUnique({ where: { email: session.user.email }, select: { id: true, systemRole: true, permissionOverrides: true }, }) : null; // Track user activity (throttled, fire-and-forget) if (dbUser) trackActivity(dbUser.id); // Load configurable role defaults (cached, 60s TTL) const roleDefaults = await loadRoleDefaults(); // eslint-disable-next-line @typescript-eslint/no-explicit-any const options: any = { endpoint: "/api/trpc", req, router: appRouter, createContext: () => createTRPCContext({ session, dbUser, roleDefaults }), }; if (process.env["NODE_ENV"] === "development") { options.onError = ({ path, error, }: { path?: string; error: { message: string; code?: string }; }) => { const label = `tRPC ${path ?? ""}`; if (error.code === "NOT_FOUND") { console.warn(`⚠️ ${label}: ${error.message}`); return; } console.error(`❌ ${label}: ${error.message}`); }; } return fetchRequestHandler(options); }; export { handler as GET, handler as POST };