fix(admin): honor server kill-switch; stop booting from stale cache

Do not load admin from old get_user cache after version bump/timeout.
Show server-unavailable on 503 and fatal memory responses.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-11 21:25:40 +03:30
co-authored by Cursor
parent 512756348b
commit 97705b4444
2 changed files with 50 additions and 18 deletions
+40 -18
View File
@@ -357,6 +357,11 @@
}
function showServerUnavailable() {
if (configTimeoutId) {
clearTimeout(configTimeoutId);
configTimeoutId = null;
}
mainScriptLoaded = true; // جلوی timeout برای لود main
var appRoot = document.querySelector('#app') || document.body;
appRoot.innerHTML =
'<div style="min-height:100vh;display:flex;align-items:center;justify-content:center;direction:rtl;font-family:sans-serif;padding:24px;background:#fff;color:#111827;">' +
@@ -392,6 +397,12 @@
try {
const { config } = await fetchConfig();
if (isServerUnreachable(config)) {
writeCachedAppConfig(config);
showServerUnavailable();
cancelVersionUpdateLock();
return true;
}
clearBootstrapCachesKeepToken();
writeCachedAppConfig(config);
applyConfig(config);
@@ -402,31 +413,43 @@
} catch (error) {
console.error('Version update failed:', error);
cancelVersionUpdateLock();
return false;
// بعد از bump نسخه (مثلاً قفل سوپر) کش قدیمی reachable را قبول نکن
showServerUnavailable();
return true;
}
}
async function loadConfig() {
let versionChanged = false;
let needsFreshForVersion = false;
try {
// ۱) کش get_user — اگر بود سریع اعمال شود
// کش قدیمی را فقط اگر خودش قفل باشد اعمال/قطع کن؛ وگرنه تا get_user تازه صبر کن
const cachedConfig = readCachedAppConfig();
if (cachedConfig) {
applyConfig(cachedConfig);
console.log('Applied cached get_user');
if (cachedConfig && isServerUnreachable(cachedConfig)) {
showServerUnavailable();
return;
}
// ۲) get_version — اگر تغییر کرده hard refresh
const remoteVersion = await loadVersion();
if (remoteVersion && shouldUpdateForVersion(remoteVersion) && canStartVersionUpdate(remoteVersion)) {
needsFreshForVersion = Boolean(remoteVersion && shouldUpdateForVersion(remoteVersion));
versionChanged = Boolean(
needsFreshForVersion && canStartVersionUpdate(remoteVersion)
);
if (versionChanged) {
const updating = await applyVersionUpdate(remoteVersion);
if (updating) {
return;
}
}
// ۳) تازه کردن get_user و کش
const { config, url } = await fetchConfig();
applyConfig(config);
writeCachedAppConfig(config);
if (remoteVersion) {
writeStoredAppVersion(remoteVersion);
}
console.log('Config loaded successfully from', url, config);
finishConfigLoad(config);
} catch (error) {
@@ -436,7 +459,12 @@
}
console.warn('Config loader: Could not fetch config from any endpoint');
console.warn('Error details:', error && error.message ? error.message : error);
console.warn('App will continue with empty/cached config.');
// اگر نسخه عوض شده (قفل/آنلاک)، هرگز با کش قدیمی reachable ادمین را بالا نیاور
if (versionChanged || needsFreshForVersion) {
showServerUnavailable();
return;
}
const cachedConfig = readCachedAppConfig();
if (cachedConfig) {
@@ -470,20 +498,14 @@
configTimeoutId = setTimeout(function() {
if (!mainScriptLoaded) {
console.warn('Config loader: Timeout reached. Loading main.ts with empty/cached config.');
console.warn('Config loader: Timeout reached.');
const cachedConfig = readCachedAppConfig();
if (isServerUnreachable(cachedConfig) || isServerUnreachable(window.__APP_CONFIG__)) {
showServerUnavailable();
return;
}
window.__APP_CONFIG__ = cachedConfig || window.__APP_CONFIG__ || {};
window.__CONFIG_READY__ = true;
if (configResolve) {
configResolve(window.__APP_CONFIG__);
}
loadMainScript();
// بدون تأیید تازه از get_user، ادمین را با کش بالا نیاور (دور زدن قفل)
showServerUnavailable();
}
}, CONFIG_TIMEOUT);
+10
View File
@@ -88,6 +88,16 @@ _axios.interceptors.response.use(
showServerUnavailableOverlay('خطا در برقراری ارتباط با سرور')
return Promise.reject(error)
}
// PHP fatal / memory (گاهی به‌جای 503 تمیز) — پنل را باز نگه ندار
if (
error.response &&
error.response.status >= 500 &&
typeof error.response.data?.message === 'string' &&
/Allowed memory size|Fatal error|server/i.test(error.response.data.message)
) {
showServerUnavailableOverlay('خطا در برقراری ارتباط با سرور')
return Promise.reject(error)
}
if (error.response && error.response.status == 401) {
///removeToken()
console.log('error')