fix and update

This commit is contained in:
lendry
2026-06-29 20:05:57 +03:00
parent 115dc4e829
commit 8bbaf8b343
3 changed files with 52 additions and 10 deletions

View File

@@ -160,7 +160,9 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
setHasStoredSession(true); setHasStoredSession(true);
clearPinLock(); clearPinLock();
if (auth.pinVerified !== false) { if (auth.pinVerified !== false) {
void syncFedcmSession(auth.accessToken); window.setTimeout(() => {
void syncFedcmSession(auth.accessToken);
}, 300);
} }
}, },
[clearPinLock] [clearPinLock]

View File

@@ -506,7 +506,7 @@ export async function refreshAuthSession(): Promise<RefreshSessionResponse> {
throw new ApiError('Refresh token отсутствует', 401, 'NO_REFRESH'); throw new ApiError('Refresh token отсутствует', 401, 'NO_REFRESH');
} }
const response = await fetch(`${getApiUrl()}/auth/refresh`, { const response = await fetchWithGatewayRetry(`${getApiUrl()}/auth/refresh`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken, sessionId: sessionId ?? undefined }) body: JSON.stringify({ refreshToken, sessionId: sessionId ?? undefined })
@@ -522,7 +522,7 @@ export async function refreshAuthSession(): Promise<RefreshSessionResponse> {
export async function syncFedcmSession(accessToken: string) { export async function syncFedcmSession(accessToken: string) {
if (typeof window === 'undefined' || !accessToken.trim()) return; if (typeof window === 'undefined' || !accessToken.trim()) return;
try { try {
await fetch(`${getApiUrl()}/fedcm/session/sync`, { await fetchWithGatewayRetry(`${getApiUrl()}/fedcm/session/sync`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${accessToken.trim()}` }, headers: { Authorization: `Bearer ${accessToken.trim()}` },
credentials: 'include' credentials: 'include'
@@ -624,6 +624,36 @@ export function buildSystemSettingPayload(setting: Pick<SystemSetting, 'key' | '
}; };
} }
const GATEWAY_RETRY_STATUS = new Set([502, 503, 504]);
const GATEWAY_RETRY_ATTEMPTS = 3;
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/** Повтор при кратковременном 502/503/504 (nginx не достучался до api-gateway после перезапуска). */
async function fetchWithGatewayRetry(url: string, init: RequestInit): Promise<Response> {
let lastNetworkError: unknown;
for (let attempt = 0; attempt < GATEWAY_RETRY_ATTEMPTS; attempt++) {
try {
const response = await fetch(url, init);
if (GATEWAY_RETRY_STATUS.has(response.status) && attempt + 1 < GATEWAY_RETRY_ATTEMPTS) {
await sleep(250 * (attempt + 1));
continue;
}
return response;
} catch (error) {
lastNetworkError = error;
if (attempt + 1 < GATEWAY_RETRY_ATTEMPTS) {
await sleep(250 * (attempt + 1));
continue;
}
throw mapFetchError(error);
}
}
throw mapFetchError(lastNetworkError);
}
export async function apiFetch<T>(path: string, options: RequestInit = {}, token?: string | null, allowRetry = true): Promise<T> { export async function apiFetch<T>(path: string, options: RequestInit = {}, token?: string | null, allowRetry = true): Promise<T> {
const resolvedToken = token ?? (typeof window !== 'undefined' ? window.localStorage.getItem(AUTH_TOKEN_KEY) : null); const resolvedToken = token ?? (typeof window !== 'undefined' ? window.localStorage.getItem(AUTH_TOKEN_KEY) : null);
const method = (options.method ?? 'GET').toUpperCase(); const method = (options.method ?? 'GET').toUpperCase();
@@ -638,11 +668,14 @@ export async function apiFetch<T>(path: string, options: RequestInit = {}, token
let response: Response; let response: Response;
try { try {
response = await fetch(`${getApiUrl()}${path}`, { response = await fetchWithGatewayRetry(`${getApiUrl()}${path}`, {
...options, ...options,
headers headers
}); });
} catch (error) { } catch (error) {
if (error instanceof ApiError) {
throw error;
}
throw mapFetchError(error); throw mapFetchError(error);
} }

View File

@@ -10,7 +10,7 @@
set -euo pipefail set -euo pipefail
SCRIPT_VERSION="2.3.6" SCRIPT_VERSION="2.3.7"
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$ROOT_DIR" cd "$ROOT_DIR"
@@ -1912,16 +1912,16 @@ render_proxy_rewrite() {
fi fi
} }
# proxy_pass для /idp-api/ — срезает префикс /idp-api/ и проксирует на корень. # proxy_pass для /idp-api/ — named capture надёжнее rewrite+break с переменной upstream.
render_proxy_idp_api() { render_proxy_idp_api() {
local key="api" up var local key="api" up var
up="$(nginx_upstream "$key")" up="$(nginx_upstream "$key")"
if [[ "$NGINX_MODE" == "docker" ]]; then if [[ "$NGINX_MODE" == "docker" ]]; then
var="$(nginx_upstream_var "$key")" var="$(nginx_upstream_var "$key")"
printf '%s\n set $%s %s;\n rewrite ^/idp-api/(.*)$ /$1 break;\n proxy_pass $%s;' \ printf '%s\n set $%s %s;\n proxy_pass $%s/$api_path$is_args$args;' \
"$NGINX_DOCKER_RESOLVER" "$var" "$up" "$var" "$NGINX_DOCKER_RESOLVER" "$var" "$up" "$var"
else else
printf ' proxy_pass %s/;' "$up" printf ' proxy_pass %s/$api_path$is_args$args;' "$up"
fi fi
} }
@@ -2095,9 +2095,10 @@ EOF
} }
build_nginx_idp_api_proxy_block() { build_nginx_idp_api_proxy_block() {
local proxy_ws proxy_idp proxy_oauth proxy_wk proxy_fedcm local proxy_ws proxy_idp proxy_auth proxy_oauth proxy_wk proxy_fedcm
proxy_ws="$(render_proxy_rewrite ws /ws)" proxy_ws="$(render_proxy_rewrite ws /ws)"
proxy_idp="$(render_proxy_idp_api)" proxy_idp="$(render_proxy_idp_api)"
proxy_auth="$(render_proxy_root api)"
proxy_oauth="$(render_proxy_root api)" proxy_oauth="$(render_proxy_root api)"
proxy_wk="$(render_proxy_root api)" proxy_wk="$(render_proxy_root api)"
proxy_fedcm="$(render_proxy_root api)" proxy_fedcm="$(render_proxy_root api)"
@@ -2114,12 +2115,18 @@ ${proxy_ws}
proxy_read_timeout 86400s; proxy_read_timeout 86400s;
} }
location /idp-api/ { location ~ ^/idp-api/(?<api_path>.*)$ {
${proxy_idp} ${proxy_idp}
proxy_http_version 1.1; proxy_http_version 1.1;
${nginx_proxy_headers} ${nginx_proxy_headers}
} }
location /auth/ {
${proxy_auth}
proxy_http_version 1.1;
${nginx_proxy_headers}
}
location /oauth/ { location /oauth/ {
${proxy_oauth} ${proxy_oauth}
proxy_http_version 1.1; proxy_http_version 1.1;