diff --git a/VERSION b/VERSION index c492825..3cf5751 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.5.6 +3.5.7 diff --git a/play-life-web/package.json b/play-life-web/package.json index 973fa67..37a9ba8 100644 --- a/play-life-web/package.json +++ b/play-life-web/package.json @@ -1,6 +1,6 @@ { "name": "play-life-web", - "version": "3.5.6", + "version": "3.5.7", "type": "module", "scripts": { "dev": "vite", diff --git a/play-life-web/src/components/auth/AuthContext.jsx b/play-life-web/src/components/auth/AuthContext.jsx index c1c847f..cd488e8 100644 --- a/play-life-web/src/components/auth/AuthContext.jsx +++ b/play-life-web/src/components/auth/AuthContext.jsx @@ -1,4 +1,4 @@ -import React, { createContext, useContext, useState, useEffect, useCallback } from 'react' +import React, { createContext, useContext, useState, useEffect, useCallback, useRef } from 'react' const AuthContext = createContext(null) @@ -10,6 +10,9 @@ export function AuthProvider({ children }) { const [user, setUser] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) + + // Ref для синхронизации параллельных refresh-запросов + const refreshPromiseRef = useRef(null) const logout = useCallback(async () => { const token = localStorage.getItem(TOKEN_KEY) @@ -34,7 +37,8 @@ export function AuthProvider({ children }) { setUser(null) }, []) - const refreshToken = useCallback(async () => { + // Внутренняя функция для выполнения refresh + const doRefreshToken = useCallback(async () => { const refresh = localStorage.getItem(REFRESH_TOKEN_KEY) if (!refresh) { @@ -84,6 +88,25 @@ export function AuthProvider({ children }) { } }, []) + // Синхронизированная функция refresh - предотвращает race condition + // Если refresh уже выполняется, все вызовы ждут его завершения + const refreshToken = useCallback(async () => { + // Если refresh уже выполняется, ждём его завершения + if (refreshPromiseRef.current) { + console.log('[Auth] Refresh already in progress, waiting...') + return refreshPromiseRef.current + } + + // Создаём promise для refresh и сохраняем его + console.log('[Auth] Starting token refresh...') + refreshPromiseRef.current = doRefreshToken().finally(() => { + // Очищаем ref после завершения (успешного или нет) + refreshPromiseRef.current = null + }) + + return refreshPromiseRef.current + }, [doRefreshToken]) + // Initialize from localStorage useEffect(() => { const initAuth = async () => {