diff --git a/src/app/routes/__root.tsx b/src/app/routes/__root.tsx index e31f413..fae7445 100644 --- a/src/app/routes/__root.tsx +++ b/src/app/routes/__root.tsx @@ -122,26 +122,12 @@ export const Route = createRootRouteWithContext<{ context.queryClient, playerQueries.auth() ); + + console.log('__root beforeLoad auth data:', auth); + return { auth }; } catch (error: any) { - if (typeof window !== 'undefined') { - const { doesSessionExist } = await import('supertokens-web-js/recipe/session'); - const { refreshManager } = await import('@/lib/supertokens/refresh-manager'); - - const sessionExists = await doesSessionExist(); - if (sessionExists) { - try { - await refreshManager.refresh(); - const auth = await ensureServerQueryData( - context.queryClient, - playerQueries.auth() - ); - return { auth }; - } catch { - return {}; - } - } - } + console.error('__root beforeLoad error:', error); return {}; } }, diff --git a/src/app/routes/_authed.tsx b/src/app/routes/_authed.tsx index d024d51..5ffac39 100644 --- a/src/app/routes/_authed.tsx +++ b/src/app/routes/_authed.tsx @@ -5,10 +5,14 @@ import { Flex, Loader } from "@mantine/core"; export const Route = createFileRoute("/_authed")({ beforeLoad: ({ context }) => { + console.log('_authed beforeLoad context:', context.auth); + if (!context.auth?.user) { + console.log('_authed: No user in context, redirecting to login'); throw redirect({ to: "/login" }); } + console.log('_authed: User found, allowing access'); return { auth: { ...context.auth, diff --git a/src/components/session-monitor.tsx b/src/components/session-monitor.tsx index 0c53d45..bec0a9c 100644 --- a/src/components/session-monitor.tsx +++ b/src/components/session-monitor.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef } from 'react'; -import { doesSessionExist } from 'supertokens-web-js/recipe/session'; import { refreshManager } from '@/lib/supertokens/refresh-manager'; import { logger } from '@/lib/supertokens'; +import { ensureSuperTokensFrontend } from '@/lib/supertokens/client'; export function SessionMonitor() { const lastRefreshTimeRef = useRef(0); @@ -27,10 +27,13 @@ export function SessionMonitor() { } try { + ensureSuperTokensFrontend(); + + const { doesSessionExist } = await import('supertokens-web-js/recipe/session'); + const sessionExists = await doesSessionExist(); if (!sessionExists) { - logger.info('Session monitor: no session exists, redirecting to login'); - window.location.href = '/login'; + logger.info('Session monitor: no session exists, skipping refresh'); return; } @@ -42,17 +45,13 @@ export function SessionMonitor() { lastRefreshTimeRef.current = Date.now(); logger.info('Session monitor: session refreshed successfully'); } else { - logger.warn('Session monitor: refresh returned false, redirecting to login'); - window.location.href = '/login'; + logger.warn('Session monitor: refresh returned false'); } - } catch (error) { - logger.error('Session monitor: error refreshing session', error); - window.location.href = '/login'; + } catch (error: any) { + logger.error('Session monitor: error refreshing session', error?.message); } }; - handleVisibilityChange(); - document.addEventListener('visibilitychange', handleVisibilityChange); return () => { diff --git a/src/features/players/server.ts b/src/features/players/server.ts index 56874e1..c0c9969 100644 --- a/src/features/players/server.ts +++ b/src/features/players/server.ts @@ -10,29 +10,50 @@ import { toServerResult } from "@/lib/tanstack-query/utils/to-server-result"; import { serverFnLoggingMiddleware } from "@/utils/activities"; export const fetchMe = createServerFn() - .handler(async () => + .handler(async () => toServerResult(async () => { const request = getRequest(); - + try { const context = await getSessionContext(request); - + await pbAdmin.authPromise; const result = await pbAdmin.getPlayerByAuthId(context.userAuthId); return { - user: result || undefined, - roles: context.roles, + user: result || undefined, + roles: context.roles, metadata: context.metadata, phone: context.phone }; } catch (error: any) { - // logger.info("FetchMe: Session error", error) - if (error?.response?.status === 401) { - const errorData = error?.response?.data; - if (errorData?.error === "SESSION_REFRESH_REQUIRED") { + logger.info("FetchMe: Error caught", { + message: error?.message, + isResponse: error instanceof Response, + status: error instanceof Response ? error.status : error?.response?.status + }); + + if (error instanceof Response) { + const status = error.status; + if (status === 440) { + logger.info("FetchMe: Session refresh required (440)"); throw error; } } + + if (error?.response?.status === 440 || error?.response?.status === 401) { + const errorData = error?.response?.data; + if (errorData?.error === "SESSION_REFRESH_REQUIRED") { + logger.info("FetchMe: Session refresh required (legacy)"); + throw error; + } + } + + if (error?.message === "Unauthenticated") { + logger.info("FetchMe: No authenticated user (expected when not logged in)"); + return { user: undefined, roles: [], metadata: {}, phone: undefined }; + } + + logger.warn("FetchMe: Unexpected error, returning default", error); return { user: undefined, roles: [], metadata: {}, phone: undefined }; } }) diff --git a/src/lib/tanstack-query/utils/global-error-handler.ts b/src/lib/tanstack-query/utils/global-error-handler.ts index ed9aa33..c4a5ec2 100644 --- a/src/lib/tanstack-query/utils/global-error-handler.ts +++ b/src/lib/tanstack-query/utils/global-error-handler.ts @@ -6,40 +6,46 @@ export async function handleQueryError(error: any): Promise { throw error; } - const isSessionExpired = - error?.response?.status === 440 || - error?.response?.headers?.get?.('X-Session-Expired') === 'true'; - - if (isSessionExpired) { - try { - const errorData = await error.response.json().catch(() => ({})); - - if (errorData.error === 'SESSION_REFRESH_REQUIRED' && errorData.shouldRetry) { - logger.warn('Query detected SESSION_REFRESH_REQUIRED, initiating redirect'); - - const currentUrl = window.location.pathname + window.location.search; - await refreshManager.redirectToRefresh(currentUrl); - - throw new Error('Redirecting to refresh session'); - } - } catch (parseError) { - if (error?.response?.status === 440) { - logger.warn('Session expired (440), redirecting to refresh'); - const currentUrl = window.location.pathname + window.location.search; - await refreshManager.redirectToRefresh(currentUrl); - throw new Error('Redirecting to refresh session'); - } - } + if (!error || typeof error !== 'object') { + throw error; } - if (error?.response?.status === 401) { - try { - const errorData = typeof error.response.data === 'string' - ? JSON.parse(error.response.data) - : error.response.data; + if (error instanceof Response) { + const status = error.status; - if (errorData?.error === 'SESSION_REFRESH_REQUIRED') { - logger.warn('Query detected legacy SESSION_REFRESH_REQUIRED (401), initiating redirect'); + if (status === 440) { + try { + const errorData = await error.json(); + + if (errorData?.error === 'SESSION_REFRESH_REQUIRED' && errorData?.shouldRetry === true) { + logger.warn('Query detected SESSION_REFRESH_REQUIRED (Response), initiating redirect'); + + const currentUrl = window.location.pathname + window.location.search; + await refreshManager.redirectToRefresh(currentUrl); + + throw new Error('Redirecting to refresh session'); + } + } catch (parseError) { + } + } + throw error; + } + + const status = error?.response?.status; + + if (status === 440) { + try { + let errorData = error?.response?.data; + + if (typeof errorData === 'string') { + try { + errorData = JSON.parse(errorData); + } catch { + } + } + + if (errorData?.error === 'SESSION_REFRESH_REQUIRED' && errorData?.shouldRetry === true) { + logger.warn('Query detected SESSION_REFRESH_REQUIRED (legacy format), initiating redirect'); const currentUrl = window.location.pathname + window.location.search; await refreshManager.redirectToRefresh(currentUrl);