From 5f1edc31741780aae6c68fc74f849b62829a42a6 Mon Sep 17 00:00:00 2001 From: NeilClack Date: Tue, 7 Jul 2026 09:14:14 -0500 Subject: [PATCH] fix: prevent redirect loop on /account/setup for users without profile - Skip profile redirect when already on /account/setup so users who just signed up/logged in land on the page without looping - Add test for the skip-redirect case --- src/routes/(protected)/+layout.server.ts | 5 +++-- src/routes/(protected)/layout.server.spec.ts | 12 +++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/routes/(protected)/+layout.server.ts b/src/routes/(protected)/+layout.server.ts index 373710c..07bb9ad 100644 --- a/src/routes/(protected)/+layout.server.ts +++ b/src/routes/(protected)/+layout.server.ts @@ -2,7 +2,7 @@ import type { LayoutServerLoad } from './$types'; import { error, redirect } from '@sveltejs/kit'; import { prisma } from '$lib/db'; -export const load: LayoutServerLoad = async ({ locals }) => { +export const load: LayoutServerLoad = async ({ locals, url }) => { if (!locals.user?.id) { throw error(403, 'not authorized'); } @@ -14,7 +14,8 @@ export const load: LayoutServerLoad = async ({ locals }) => { if (!user) { throw error(403, 'not authorized'); } - if (!user.profile) { + if (!user.profile && !url.pathname.startsWith('/account/setup')) { + // Skip redirect when already on /account/setup to avoid redirect loop throw redirect(303, '/account/setup'); } diff --git a/src/routes/(protected)/layout.server.spec.ts b/src/routes/(protected)/layout.server.spec.ts index 094304a..ece0d57 100644 --- a/src/routes/(protected)/layout.server.spec.ts +++ b/src/routes/(protected)/layout.server.spec.ts @@ -41,7 +41,8 @@ describe('(protected) layout server load', () => { findUnique.mockResolvedValue({ id: 'user-1', roleId: null, profile: null }); const locals = createLocals(mockUser() as any); - const err = await Promise.resolve(load({ locals } as any)).catch((e: unknown) => e); + const url = new URL('http://localhost/dashboard'); + const err = await Promise.resolve(load({ locals, url } as any)).catch((e: unknown) => e); expect(isRedirect(err)).toBe(true); if (isRedirect(err)) { expect(err.status).toBe(303); @@ -49,6 +50,15 @@ describe('(protected) layout server load', () => { } }); + it('skips redirect when already on /account/setup', async () => { + findUnique.mockResolvedValue({ id: 'user-1', roleId: null, profile: null }); + + const locals = createLocals(mockUser() as any); + const url = new URL('http://localhost/account/setup'); + const result = await load({ locals, url } as any); + expect(result).toEqual({ userRoleId: null }); + }); + it('returns userRoleId when user has a profile', async () => { findUnique.mockResolvedValue(mockUserWithProfile({ roleId: 2 }));