import { redirect } from '@sveltejs/kit'; import { env } from '$env/dynamic/private'; import type { LayoutServerLoad } from './$types'; import { validateAuth, getAuthTokens, getUserCompanies, clearAuthTokens } from '$lib/server/api'; import { redirectToWorkspaceLogin } from '$lib/server/workspace-auth'; import { extractAllowedSystemsFromToken, mergeTokenClaims, resolveActiveCompanyId, resolveSystemGate, setActiveSystemCookie, redirectToWorkspaceBase } from '$lib/server/system-gate'; export const load: LayoutServerLoad = async ({ cookies, url, fetch }) => { // Verificar si existe el token en las cookies const { accessToken } = getAuthTokens(cookies); console.log('[dashboard layout] access_token presente:', !!accessToken, '| url:', url.pathname); if (!accessToken) { redirectToWorkspaceLogin(cookies, url); } // Validar el token con el backend y obtener datos del usuario // La función validateAuth maneja automáticamente el refresh de tokens const redirectOnFail = undefined; try { // Primero my-companies: ejecuta get_current_user y puede crear tenant/empresa/usuario // antes de /me/profile en validateAuth (evita SSR sin la empresa recién provisionada). const companies = await getUserCompanies(cookies, fetch); const userData = await validateAuth(cookies, fetch, redirectOnFail); const tokenClaims = mergeTokenClaims(userData, accessToken); const gate = resolveSystemGate({ tokenClaims, cookieSystem: cookies.get('active_system') ?? null, requestedSystem: url.searchParams.get('active_system') ?? null }); const activeCompanyId = resolveActiveCompanyId(cookies, companies); const allowedSystemsFromToken = extractAllowedSystemsFromToken(tokenClaims); if (gate.action === 'redirect_workspace') { redirectToWorkspaceBase(); } // Si el JWT no trae el claim allowed_systems pero el gate resolvió un sistema, // usar el sistema activo como mínimo para que el store pueda inicializarse. const allowedSystems = allowedSystemsFromToken.length > 0 ? allowedSystemsFromToken : [gate.activeSystem]; setActiveSystemCookie(cookies, gate.activeSystem); // Cargar los tenants del usuario desde Hub (fuente de verdad multi-tenant) let userTenants: { id: number; name: string; slug: string }[] = []; try { const hubUrl = (env.INTERNAL_HUB_URL || env.HUB_URL || 'http://localhost:8001').replace(/\/+$/, ''); const tenantOverride = cookies.get('sso_tenant_id'); const tenantsRes = await fetch(`${hubUrl}/api/v1/auth/my-tenants`, { headers: { 'Authorization': `Bearer ${accessToken}`, ...(tenantOverride ? { 'X-Tenant-Override': tenantOverride } : {}), }, }); if (tenantsRes.ok) { userTenants = await tenantsRes.json(); } } catch { // No bloquear el dashboard si falla la carga de tenants } return { authenticated: true, user: { ...userData, token: accessToken, allowedSystems }, companies, activeCompanyId: activeCompanyId ?? undefined, activeSystem: gate.activeSystem, allowedSystems, userTenants, error: undefined }; } 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 clearAuthTokens(cookies); redirectToWorkspaceLogin(cookies, url); } };