apiFetch оборачивает сбой сети в ApiError(0, NETWORK) и не-JSON тело 2xx в ApiError(BAD_RESPONSE); AbortError пробрасывается как есть, пустое тело даёт undefined. В production-ветке входа показываются ошибка загрузки профиля и кнопка «Повторить», форма dev-входа по-прежнему вырезается из бандла литералом process.env.NODE_ENV. Мелочи: «Сессия истекла» при 401, trim и whitespace-правило для email, центрирование по 100svh, union-типы прав, срез хвостовых слэшей в API_BASE. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
34 lines
1.4 KiB
TypeScript
34 lines
1.4 KiB
TypeScript
// Токен доступа живёт в sessionStorage: пропадает при закрытии вкладки и не доступен другим вкладкам (design D-9).
|
||
// Любой доступ к хранилищу обёрнут в try/catch: в приватном режиме или при заблокированных данных сайта оно может
|
||
// бросать исключение — тогда токен хранится только в памяти страницы, а приложение продолжает работать.
|
||
const KEY = 'armka.token';
|
||
|
||
let memoryToken: string | null = null;
|
||
|
||
// Приоритет у sessionStorage (общий для вкладки); токен в памяти — только запасной вариант, когда хранилище недоступно
|
||
export function getToken(): string | null {
|
||
try {
|
||
return sessionStorage.getItem(KEY) ?? memoryToken;
|
||
} catch {
|
||
return memoryToken;
|
||
}
|
||
}
|
||
|
||
export function setToken(token: string): void {
|
||
memoryToken = token;
|
||
try {
|
||
sessionStorage.setItem(KEY, token);
|
||
} catch {
|
||
// хранилище недоступно: остаётся токен в памяти
|
||
}
|
||
}
|
||
|
||
export function clearToken(): void {
|
||
memoryToken = null;
|
||
try {
|
||
sessionStorage.removeItem(KEY);
|
||
} catch {
|
||
// хранилище недоступно: токен в памяти уже сброшен
|
||
}
|
||
}
|