Files
plantillas-proyectos/frontend/src/routes/dashboard/+layout.server.ts

121 lines
3.8 KiB
TypeScript

import { redirect } from '@sveltejs/kit';
import type { LayoutServerLoad } from './$types';
export const load: LayoutServerLoad = async ({ cookies, url, fetch }) => {
// Verificar si existe el token en las cookies
let token = cookies.get('access_token');
const refreshToken = cookies.get('refresh_token');
// Si no hay token, redirigir al login
if (!token) {
// Guardar la URL a la que intentaba acceder para redirigir después del login
throw redirect(303, `/login?redirect=${encodeURIComponent(url.pathname)}`);
}
// Configurar la URL de la API
let apiUrl = process.env.INTERNAL_API_URL;
if (!apiUrl) {
apiUrl = import.meta.env.VITE_API_URL;
// Reemplazar 'localhost' con 'backend' para llamadas desde el servidor (SSR)
apiUrl = apiUrl?.replace('localhost', 'backend').replace('127.0.0.1', 'backend');
}
// Normalizar la URL: asegurar que termine con '/'
const baseUrl = apiUrl?.endsWith('/') ? apiUrl : `${apiUrl}/`;
// Validar el token con el backend para asegurar que sea válido
try {
const response = await fetch(`${baseUrl}v1/auth/me`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
// Si el token está expirado (401) y tenemos refresh token, intentar refrescar
if (response.status === 401 && refreshToken) {
try {
const refreshResponse = await fetch(`${baseUrl}v1/auth/refresh`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ refresh_token: refreshToken })
});
if (refreshResponse.ok) {
const refreshData = await refreshResponse.json();
// Actualizar las cookies con los nuevos tokens
cookies.set('access_token', refreshData.access_token, {
path: '/',
httpOnly: false,
sameSite: 'lax',
secure: process.env.NODE_ENV === 'production',
maxAge: 60 * 60 * 24 * 7 // 7 días
});
if (refreshData.refresh_token) {
cookies.set('refresh_token', refreshData.refresh_token, {
path: '/',
httpOnly: false,
sameSite: 'lax',
secure: process.env.NODE_ENV === 'production',
maxAge: 60 * 60 * 24 * 30 // 30 días
});
}
// Usar el nuevo token para obtener la info del usuario
token = refreshData.access_token;
// Reintentar la validación con el nuevo token
const retryResponse = await fetch(`${baseUrl}v1/auth/me`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (retryResponse.ok) {
const userData = await retryResponse.json();
return {
authenticated: true,
user: userData
};
}
}
} catch (refreshError) {
console.error('🔐 [Dashboard] Error al refrescar token:', refreshError);
}
// Si llegamos aquí, el refresh falló
cookies.delete('access_token', { path: '/' });
cookies.delete('refresh_token', { path: '/' });
throw redirect(303, `/login?redirect=${encodeURIComponent(url.pathname)}`);
}
if (!response.ok) {
// Token inválido y no se pudo refrescar, limpiar y redirigir
cookies.delete('access_token', { path: '/' });
cookies.delete('refresh_token', { path: '/' });
throw redirect(303, `/login?redirect=${encodeURIComponent(url.pathname)}`);
}
const userData = await response.json();
return {
authenticated: true,
user: userData
};
} catch (error) {
// Si es un redirect, re-lanzarlo sin tocar las cookies
if (error && typeof error === 'object' && 'status' in error && 'location' in error) {
throw error;
}
// Para cualquier otro error (conexión, etc), limpiar token y redirigir
console.error('🔐 [Dashboard] Error validando token:', error);
cookies.delete('access_token', { path: '/' });
cookies.delete('refresh_token', { path: '/' });
throw redirect(303, `/login?redirect=${encodeURIComponent(url.pathname)}`);
}
};