/
kreyndelHam
/
Konstructorium
Обзор
Документация
Войти
/
kreyndelHam
/
Konstructorium
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
1
CI/CD
Аналитика
Безопасность
dev
frontend/src/utils/authBootstrap.js
129 строк
3 KB
kreindel.s
Fix front
23 май 2026, 11:29
23 май 2026, 11:29
a529735
Код
Авторство
О чём код?
/** * Startup auth probe helpers: retry transient failures and avoid false logouts. */ const DEFAULT_RETRY_DELAY_MS = 400 /** * @typedef {'authenticated' | 'unauthorized' | 'offline'} AuthBootstrapStatus */ /** * @typedef {object} AuthBootstrapResult * @property {AuthBootstrapStatus} status * @property {object|null} [user] * @property {boolean} shouldClearAuth */ /** * Pause execution between auth probe retries. * * @param {number} ms * @returns {Promise<void>} */ const delay = (ms) => new Promise((resolve) => { setTimeout(resolve, ms) }) /** * Return true when the error is likely transient (network or server fault). * * @param {import('axios').AxiosError|Error} error * @returns {boolean} */ export const isTransientAuthProbeError = (error) => { if (!error?.response) { return true } const status = error.response.status return status >= 500 || status === 408 || status === 429 } /** * Probe backend session on app startup with retries. * * Clears stored auth only when the server explicitly rejects credentials (401/403). * Keeps local snapshot on offline/5xx so refresh does not log users out unnecessarily. * * @param {object} options * @param {() => Promise<{data: object}>} options.getProfile * @param {() => Promise<unknown>} [options.warmCsrf] Optional CSRF cookie refresh before retry. * @param {() => boolean} [options.hasStoredCredentials] Whether local token/user snapshot exists. * @param {number} [options.maxAttempts] * @param {number} [options.retryDelayMs] * @returns {Promise<AuthBootstrapResult>} */ export const resolveAuthOnStartup = async ({ getProfile, warmCsrf, hasStoredCredentials = () => false, maxAttempts = 2, retryDelayMs = DEFAULT_RETRY_DELAY_MS, }) => { let lastError = null for (let attempt = 1; attempt <= maxAttempts; attempt += 1) { try { const response = await getProfile() if (response?.data) { return { status: 'authenticated', user: response.data, shouldClearAuth: false, } } return { status: 'unauthorized', user: null, shouldClearAuth: true, } } catch (error) { lastError = error const status = error?.response?.status if (status === 401 || status === 403) { if (attempt < maxAttempts && warmCsrf) { await Promise.resolve(warmCsrf()).catch(() => { // CSRF warm-up is best-effort before the final auth probe attempt. }) await delay(retryDelayMs) continue } return { status: 'unauthorized', user: null, shouldClearAuth: true, } } if (isTransientAuthProbeError(error) && attempt < maxAttempts) { await delay(retryDelayMs) continue } if (isTransientAuthProbeError(error) && hasStoredCredentials()) { return { status: 'offline', user: null, shouldClearAuth: false, } } break } } if (hasStoredCredentials() && lastError && isTransientAuthProbeError(lastError)) { return { status: 'offline', user: null, shouldClearAuth: false, } } return { status: 'unauthorized', user: null, shouldClearAuth: true, } }