// lib/auth.config.ts import { SignInAction } from '@/feactures/auth/actions/login-action'; import { logoutAction } from '@/feactures/auth/actions/logout-action'; import { CredentialsSignin, NextAuthConfig, Session, User } from 'next-auth'; import { DefaultJWT, JWT } from 'next-auth/jwt'; import CredentialProvider from 'next-auth/providers/credentials'; // Define los tipos para tus respuestas de SignInAction interface SignInSuccessResponse { message: string; user: { email: string; username: string; id: number; rol: Array<{ id: number; rol: string }>; fullname: string; }; tokens: { access_token: string; access_expire_in: number; refresh_token: string; refresh_expire_in: number; }; } // **CAMBIO AQUÍ**: `type: string;` en lugar de una unión de literales interface SignInErrorResponse { type: string; // Si SignInAction puede devolver cualquier string aquí message: string; details?: any; } // Unión de tipos para el resultado de SignInAction, AHORA INCLUYE `null` type SignInActionResult = SignInSuccessResponse | SignInErrorResponse | null; const authConfig: NextAuthConfig = { providers: [ CredentialProvider({ credentials: { username: { type: 'username', }, password: { type: 'password', }, }, async authorize( credentials: Partial>, ): Promise { const credential = { username: credentials?.username as string, password: credentials?.password as string, }; // Asigna el tipo `SignInActionResult` que ahora incluye `null` const response: SignInActionResult = await SignInAction(credential); // **NUEVO: Manejar el caso `null` primero** if (response === null) { console.error( 'SignInAction returned null, indicating a potential issue before API call or generic error.', ); throw new CredentialsSignin('Error de inicio de sesión inesperado.'); } // Tipo Guarda: Verificar la respuesta de error if ( 'type' in response && (response.type === 'API_ERROR' || response.type === 'VALIDATION_ERROR' || response.type === 'UNKNOWN_ERROR') // Incluye todos los tipos de error posibles ) { // Si es un error, lánzalo. Este camino termina aquí. throw new CredentialsSignin('Error en la API:' + response.message); } if (!('user' in response)) { // Esto solo ocurriría si SignInAction devolvió un objeto que no es null, // no es un error conocido por 'type', PERO tampoco tiene la propiedad 'user'. // Es un caso de respuesta inesperada del API. console.error( "Respuesta de SignInAction con formato inesperado: falta la propiedad 'user'.", ); throw new CredentialsSignin( 'Error en el formato de la respuesta del servidor.', ); } return { id: response?.user.id?.toString() ?? '0', username: response?.user.username ?? '', fullname: response?.user.fullname ?? '', email: response?.user.email ?? '', role: response?.user.rol ?? [], // Add role array access_token: response?.tokens.access_token ?? '', access_expire_in: response?.tokens.access_expire_in ?? 0, }; }, }), ], pages: { signIn: '/', //sigin page }, callbacks: { async jwt({ token, user }: { user: User; token: any }) { // 1. Manejar el inicio de sesión inicial // El `user` solo se proporciona en el primer inicio de sesión. if (user) { return { id: user.id, username: user.username, fullname: user.fullname, email: user.email, role: user.role, access_token: user.access_token, access_expire_in: user.access_expire_in, }; } return token; }, async session({ session, token }: { session: Session; token: DefaultJWT }) { session.access_token = token.access_token as string; session.access_expire_in = token.access_expire_in as number; session.user = { id: token.id as number, username: token.username as string, fullname: token.fullname as string, email: token.email as string, role: token.role as Array<{ id: number; rol: string }>, }; return session; }, }, events: { async signOut(message) { // 1. verificamos que venga token (puede no venir con algunos providers) const token = (message as { token?: JWT }).token; if (!token?.access_token) return; try { await logoutAction(String(token?.id)); } catch { /* silencioso para que next-auth siempre cierre */ } }, }, } satisfies NextAuthConfig; export default authConfig;