11'use client'
22
3- import { useEffect , useRef } from 'react'
3+ import { useEffect , useRef , useState } from 'react'
44import { Chip } from '@sim/emcn'
55import { CircleAlert } from '@sim/emcn/icons'
66import { createLogger } from '@sim/logger'
@@ -27,13 +27,22 @@ function isStaleSessionError(error: unknown): boolean {
2727 return isApiClientError ( error ) && error . status === 401
2828}
2929
30- async function recoverFromStaleSession ( ) : Promise < void > {
30+ /**
31+ * Signs out (clearing every auth cookie server-side), wipes per-user client
32+ * state, and navigates to login. Returns false without navigating when the
33+ * sign-out request fails — the cookies are still set, so going to /login
34+ * would only get bounced back to /workspace by the middleware.
35+ */
36+ async function recoverFromStaleSession ( ) : Promise < boolean > {
3137 try {
32- await Promise . all ( [ signOut ( ) , clearUserData ( ) ] )
38+ await signOut ( )
3339 } catch ( error ) {
3440 logger . error ( 'Failed to sign out while recovering from a stale session:' , error )
41+ return false
3542 }
43+ await clearUserData ( )
3644 window . location . assign ( '/login' )
45+ return true
3746}
3847
3948export default function WorkspacePage ( ) {
@@ -42,6 +51,7 @@ export default function WorkspacePage() {
4251 const isAuthenticated = ! isSessionPending && ! ! session ?. user
4352 const hasRedirectedRef = useRef ( false )
4453 const isRecoveringRef = useRef ( false )
54+ const [ recoveryFailed , setRecoveryFailed ] = useState ( false )
4555
4656 const {
4757 data,
@@ -50,11 +60,15 @@ export default function WorkspacePage() {
5060 } = useWorkspacesWithMetadata ( isAuthenticated )
5161
5262 useEffect ( ( ) => {
53- if ( ! isStaleSessionError ( workspacesError ) || isRecoveringRef . current ) return
63+ if ( ! isAuthenticated || ! isStaleSessionError ( workspacesError ) || isRecoveringRef . current ) return
5464 isRecoveringRef . current = true
5565 logger . warn ( 'Session cookies are stale (authenticated session but 401 API); signing out' )
56- void recoverFromStaleSession ( )
57- } , [ workspacesError ] )
66+ void recoverFromStaleSession ( ) . then ( ( recovered ) => {
67+ if ( recovered ) return
68+ isRecoveringRef . current = false
69+ setRecoveryFailed ( true )
70+ } )
71+ } , [ isAuthenticated , workspacesError ] )
5872
5973 useEffect ( ( ) => {
6074 if ( isSessionPending || hasRedirectedRef . current ) return
@@ -98,7 +112,9 @@ export default function WorkspacePage() {
98112 } , [ session , isSessionPending , sessionError , isWorkspacesLoading , workspacesError , data , router ] )
99113
100114 const failedToLoad =
101- Boolean ( sessionError ) || ( Boolean ( workspacesError ) && ! isStaleSessionError ( workspacesError ) )
115+ recoveryFailed ||
116+ Boolean ( sessionError ) ||
117+ ( isAuthenticated && Boolean ( workspacesError ) && ! isStaleSessionError ( workspacesError ) )
102118
103119 if ( failedToLoad ) {
104120 return (
0 commit comments