Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 15 additions & 16 deletions frontend/src/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,19 @@ async function handleUnauthorized(): Promise<boolean> {
return refreshPromise
}

// Shared by `request` and `requestMultipart`: the refresh failed (or there was
// no session to refresh), so drop it and send the user back to sign in.
function dropExpiredSession(): void {
useAuthStore.getState().clearAuth()
toast('Your session has expired. Please sign in again.', 'error')
// SPA navigation, not window.location: a hard document load forces a full
// reload from the local WebView origin (capacitor://localhost on iOS,
// https://localhost on Android), which re-bootstraps the whole app and is
// unreliable for an absolute path under the capacitor:// scheme. Imported
// lazily to avoid pulling the route tree into this low-level module.
void import('../router').then(({ router }) => router.navigate({ to: '/login' }))
}

async function request<T>(path: string, options: RequestOptions = {}, isRetry = false): Promise<T> {
const { body, headers, ...rest } = options
let token = useAuthStore.getState().accessToken
Expand Down Expand Up @@ -145,14 +158,7 @@ async function request<T>(path: string, options: RequestOptions = {}, isRetry =
if (refreshed) {
return request<T>(path, options, true)
}
useAuthStore.getState().clearAuth()
toast('Your session has expired. Please sign in again.', 'error')
// SPA navigation, not window.location: a hard document load forces a full
// reload from the local WebView origin (capacitor://localhost on iOS,
// https://localhost on Android), which re-bootstraps the whole app and is
// unreliable for an absolute path under the capacitor:// scheme. Imported
// lazily to avoid pulling the route tree into this low-level module.
void import('../router').then(({ router }) => router.navigate({ to: '/login' }))
dropExpiredSession()
throw new Error('Session expired')
}

Expand Down Expand Up @@ -190,14 +196,7 @@ async function requestMultipart<T>(path: string, formData: FormData, isRetry = f
if (refreshed) {
return requestMultipart<T>(path, formData, true)
}
useAuthStore.getState().clearAuth()
toast('Your session has expired. Please sign in again.', 'error')
// SPA navigation, not window.location: a hard document load forces a full
// reload from the local WebView origin (capacitor://localhost on iOS,
// https://localhost on Android), which re-bootstraps the whole app and is
// unreliable for an absolute path under the capacitor:// scheme. Imported
// lazily to avoid pulling the route tree into this low-level module.
void import('../router').then(({ router }) => router.navigate({ to: '/login' }))
dropExpiredSession()
throw new Error('Session expired')
}

Expand Down
Loading