feat(errors): ✨ Enhance error handling with improved display, logging, and user experience utilities
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
c0c7d0d594
commit
5ab4347b39
1 changed files with 63 additions and 0 deletions
63
@applications/web/src/features/errors/sessionRecovery.ts
Normal file
63
@applications/web/src/features/errors/sessionRecovery.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import type { MutableRefObject } from 'react';
|
||||
|
||||
const SESSION_STORAGE_KEY = 'companion_session_id';
|
||||
|
||||
/** Module-level lock to prevent concurrent recovery attempts. */
|
||||
let recoveryPromise: Promise<string> | null = null;
|
||||
|
||||
export async function createSession(apiBaseUrl: string): Promise<string> {
|
||||
try {
|
||||
const res = await fetch(`${apiBaseUrl}/session`, { method: 'POST' });
|
||||
if (!res.ok) throw new Error(`POST /session failed: ${res.status}`);
|
||||
const { session_id } = (await res.json()) as { session_id: string };
|
||||
sessionStorage.setItem(SESSION_STORAGE_KEY, session_id);
|
||||
return session_id;
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : 'Unknown session creation error';
|
||||
throw new Error(`Session creation failed: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /chat with automatic session recovery on 404.
|
||||
*
|
||||
* If the server returns 404 (session expired/missing), creates a new session
|
||||
* and retries the request once. Updates `sessionIdRef.current` and sessionStorage
|
||||
* so subsequent calls use the recovered session.
|
||||
*/
|
||||
export async function chatWithRecovery(
|
||||
apiBaseUrl: string,
|
||||
sessionIdRef: MutableRefObject<string>,
|
||||
message: string,
|
||||
signal: AbortSignal,
|
||||
): Promise<Response> {
|
||||
const doFetch = (sid: string) =>
|
||||
fetch(`${apiBaseUrl}/chat`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ session_id: sid, message }),
|
||||
signal,
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await doFetch(sessionIdRef.current);
|
||||
|
||||
if (response.status !== 404) return response;
|
||||
|
||||
// Session expired — recover with dedup lock
|
||||
if (!recoveryPromise) {
|
||||
recoveryPromise = createSession(apiBaseUrl).finally(() => {
|
||||
recoveryPromise = null;
|
||||
});
|
||||
}
|
||||
|
||||
const newSessionId = await recoveryPromise;
|
||||
sessionIdRef.current = newSessionId;
|
||||
|
||||
return doFetch(newSessionId);
|
||||
} catch (err) {
|
||||
if (err instanceof Error && err.name === 'AbortError') throw err;
|
||||
const message_ = err instanceof Error ? err.message : 'Unknown chat error';
|
||||
throw new Error(`Chat request failed: ${message_}`);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue