import { db } from '@/lib/db' /** Laufzeit einer Sitzung, gleitend verlängert. */ export const SESSION_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000 /** * Erst nachschreiben, wenn eine Stunde vergangen ist. Sonst erzeugt jeder * Seitenaufruf einen Schreibvorgang, nur um den Ablauf um Sekunden zu schieben. */ const SLIDE_THRESHOLD_MS = 60 * 60 * 1000 export type ActiveSession = { id: string userId: string expiresAt: Date } export async function createSession(userId: string, userAgent?: string): Promise { const session = await db.session.create({ data: { userId, expiresAt: new Date(Date.now() + SESSION_MAX_AGE_MS), userAgent: userAgent?.slice(0, 500) ?? null, }, select: { id: true }, }) return session.id } /** * Lädt eine Sitzung und verlängert sie gleitend. Gibt `null` zurück, wenn sie * nicht mehr existiert oder abgelaufen ist. * * Die Zeile in der Datenbank ist der eigentliche Sitzungsnachweis: das Cookie * allein lässt sich nicht zurückziehen. Verliert jemand seine Rolle, löscht der * Worker die Zeile, und der nächste Request ist abgemeldet. * Siehe docs/03-auth-und-rechte.md. */ export async function loadSession(sessionId: string): Promise { const session = await db.session.findUnique({ where: { id: sessionId }, select: { id: true, userId: true, expiresAt: true, lastSeenAt: true }, }) if (!session) return null if (session.expiresAt.getTime() <= Date.now()) { await db.session.delete({ where: { id: sessionId } }).catch(() => undefined) return null } if (Date.now() - session.lastSeenAt.getTime() > SLIDE_THRESHOLD_MS) { const now = new Date() await db.session .update({ where: { id: sessionId }, data: { lastSeenAt: now, expiresAt: new Date(now.getTime() + SESSION_MAX_AGE_MS) }, }) .catch(() => undefined) } return { id: session.id, userId: session.userId, expiresAt: session.expiresAt } } export async function endSession(sessionId: string): Promise { await db.session.delete({ where: { id: sessionId } }).catch(() => undefined) } /** Wird beim Rollenverlust und beim Serveraustritt benutzt. */ export async function endAllSessionsFor(userId: string): Promise { const { count } = await db.session.deleteMany({ where: { userId } }) return count } /** Tägliche Aufräumaufgabe, siehe docs/11-betrieb.md. */ export async function deleteExpiredSessions(): Promise { const { count } = await db.session.deleteMany({ where: { expiresAt: { lte: new Date() } } }) return count }