import { auth } from "~~/lib/auth"; import { lockAdministration } from "~~/server/lib/account-security"; import { authTransaction } from "~~/server/lib/auth-transaction"; const SIGN_UP = "/api/auth/sign-up/email"; // Requests that have to be undone as a whole when they fail. The hooks in // lib/auth.ts refuse to run these without a transaction, so a URL that slips // past this list is rejected there instead of going through unguarded. const ADMIN_MUTATIONS = new Set([ "/api/auth/admin/set-role", "/api/auth/admin/ban-user", "/api/auth/admin/unban-user", "/api/auth/admin/update-user", ]); export default defineEventHandler(async (event) => { const request = toWebRequest(event); const path = new URL(request.url).pathname.replace(/\/+$/, ""); const adminMutation = ADMIN_MUTATIONS.has(path); if (request.method !== "POST" || (!adminMutation && path !== SIGN_UP)) { return auth.handler(request); } try { return await authTransaction(async (tx) => { if (adminMutation) { // Deletion, banning and demotion all wait for each other here. await lockAdministration(tx); } const response = await auth.handler(request); if (!response.ok) { // The auth handler returns errors as responses; roll back any writes. throw response; } return response; }); } catch (error) { if (error instanceof Response) { return error; } throw error; } });