Files
plantillas-proyectos/frontend/src/routes/dashboard/+layout.server.ts
2026-05-26 16:59:32 -06:00

98 lines
3.3 KiB
TypeScript

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);
}
};