Keep the longer overlay window, but stop waiting 20–25s per bootstrap request. Co-authored-by: Cursor <cursoragent@cursor.com>
662 lines
20 KiB
JavaScript
662 lines
20 KiB
JavaScript
(function() {
|
|
'use strict';
|
|
|
|
window.__APP_CONFIG__ = window.__APP_CONFIG__ || {};
|
|
window.__CONFIG_READY__ = false;
|
|
|
|
let configResolve;
|
|
let configReject;
|
|
window.__CONFIG_PROMISE__ = new Promise((resolve, reject) => {
|
|
configResolve = resolve;
|
|
configReject = reject;
|
|
});
|
|
|
|
const VERSION_SUCCESS_URL_KEY = 'VERSION_Success_URL';
|
|
const CONFIG_SUCCESS_URL_KEY = 'CONFIG_Success_URL';
|
|
const CONFIG_CACHE_KEY = 'APP_CONFIG_CACHE';
|
|
const CONFIG_IDB_NAME = 'abshode_admin_cfg';
|
|
const CONFIG_IDB_STORE = 'kv';
|
|
const CONFIG_CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
const VERSION_STORAGE_KEY = 'version';
|
|
const VERSION_UPDATE_LOCK_KEY = 'version_update_lock';
|
|
const VERSION_LAST_RELOAD_KEY = 'version_last_reload';
|
|
const AUTH_TOKEN_KEY = 'peransa_token';
|
|
const VERSION_RETRY_ROUNDS = 3;
|
|
const CONFIG_RETRY_ROUNDS = 3;
|
|
const VERSION_FETCH_TIMEOUT_MS = 10000;
|
|
const CONFIG_FETCH_TIMEOUT_MS = 10000;
|
|
const CONFIG_TIMEOUT = 60000;
|
|
|
|
let configTimeoutId;
|
|
let mainScriptLoaded = false;
|
|
|
|
function getProtocol() {
|
|
return window.location.protocol === 'https:' ? 'https:' : 'http:';
|
|
}
|
|
|
|
function resolveTenantDomain() {
|
|
const host = String(window.location.hostname || '').trim();
|
|
if (!host || host === 'localhost' || host === '127.0.0.1') {
|
|
return 'k.montzar.ir';
|
|
}
|
|
return host;
|
|
}
|
|
|
|
function isDevHost() {
|
|
const host = String(window.location.hostname || '').trim();
|
|
return host === 'localhost' || host === '127.0.0.1';
|
|
}
|
|
|
|
function getVersionUrls() {
|
|
const domain = encodeURIComponent(resolveTenantDomain());
|
|
const urls = [
|
|
'https://adm.montzar.ir/get_version?domain=' + domain,
|
|
'https://adm.montech.ir/get_version?domain=' + domain,
|
|
'https://adm.montest.ir/get_version?domain=' + domain
|
|
];
|
|
|
|
if (isDevHost()) {
|
|
urls.push(
|
|
'https://tablo.talasevin.ir/get_version',
|
|
'https://abshode-service.montgit.ir/server/get_version',
|
|
getProtocol() + '//212.23.201.173:8381/get_version',
|
|
getProtocol() + '//91.212.174.137:4040/server/get_version'
|
|
);
|
|
}
|
|
|
|
return urls;
|
|
}
|
|
|
|
function getConfigUrls() {
|
|
const protocol = getProtocol();
|
|
const domain = encodeURIComponent(resolveTenantDomain());
|
|
const urls = [
|
|
'https://adm.montzar.ir/get_user?domain=' + domain,
|
|
'https://adm.montech.ir/get_user?domain=' + domain,
|
|
'https://adm.montest.ir/get_user?domain=' + domain
|
|
];
|
|
|
|
if (isDevHost()) {
|
|
urls.push(
|
|
protocol + '//tablo.talasevin.ir/get_user',
|
|
protocol + '//abshode-service.montgit.ir/server/get_user',
|
|
protocol + '//212.23.201.173:8381/get_user',
|
|
protocol + '//91.212.174.137:4040/server/get_user'
|
|
);
|
|
}
|
|
|
|
return urls;
|
|
}
|
|
|
|
function sortUrls(urls, successKey) {
|
|
const lastSuccessUrl = localStorage.getItem(successKey);
|
|
if (!lastSuccessUrl) return urls.slice();
|
|
return [lastSuccessUrl].concat(urls.filter((url) => url !== lastSuccessUrl));
|
|
}
|
|
|
|
function clearStaleSuccessUrl(key, url) {
|
|
if (localStorage.getItem(key) === url) {
|
|
localStorage.removeItem(key);
|
|
}
|
|
}
|
|
|
|
function normalizeVersion(value) {
|
|
if (value === null || value === undefined) return '';
|
|
return String(value).trim();
|
|
}
|
|
|
|
function readUserVersion(user) {
|
|
if (!user || typeof user !== 'object' || Array.isArray(user)) return '';
|
|
const version = user.version ?? user.value;
|
|
return version === undefined || version === null ? '' : String(version).trim();
|
|
}
|
|
|
|
function normalizeVersionResponse(response) {
|
|
if (typeof response === 'string' || typeof response === 'number') {
|
|
return String(response).trim();
|
|
}
|
|
if (!response || typeof response !== 'object') return '';
|
|
|
|
if (typeof response.data === 'string' || typeof response.data === 'number') {
|
|
return String(response.data).trim();
|
|
}
|
|
|
|
const directVersion =
|
|
response.version ??
|
|
response.value ??
|
|
(response.data && typeof response.data === 'object'
|
|
? response.data.version ?? response.data.value
|
|
: undefined);
|
|
|
|
if (directVersion !== undefined && directVersion !== null) {
|
|
return String(directVersion).trim();
|
|
}
|
|
|
|
return readUserVersion(response.user);
|
|
}
|
|
|
|
function readCachedAppConfigPayload() {
|
|
try {
|
|
const raw = localStorage.getItem(CONFIG_CACHE_KEY);
|
|
if (!raw) return null;
|
|
const payload = JSON.parse(raw);
|
|
if (!payload || typeof payload !== 'object' || !payload.config) return null;
|
|
return payload;
|
|
} catch (error) {
|
|
console.warn('Failed to read cached get_user:', error);
|
|
localStorage.removeItem(CONFIG_CACHE_KEY);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function readCachedAppConfig() {
|
|
const payload = readCachedAppConfigPayload();
|
|
return payload && payload.config ? payload.config : null;
|
|
}
|
|
|
|
function isFreshGetUserCache(payload, remoteVersion, domain) {
|
|
if (!payload || !payload.config) return false;
|
|
if (isServerUnreachable(payload.config)) return false;
|
|
const cachedDomain = String(payload.domain || '').trim();
|
|
if (cachedDomain && cachedDomain !== domain) return false;
|
|
const age = Date.now() - Number(payload.cached_at || 0);
|
|
if (!payload.cached_at || age < 0 || age > CONFIG_CACHE_MAX_AGE_MS) return false;
|
|
const cachedVersion = normalizeVersion(payload.version);
|
|
if (remoteVersion) {
|
|
return cachedVersion === remoteVersion;
|
|
}
|
|
return Boolean(cachedVersion);
|
|
}
|
|
|
|
function openConfigIdb() {
|
|
return new Promise(function (resolve, reject) {
|
|
if (!window.indexedDB) {
|
|
reject(new Error('indexedDB unavailable'));
|
|
return;
|
|
}
|
|
const req = window.indexedDB.open(CONFIG_IDB_NAME, 1);
|
|
req.onupgradeneeded = function () {
|
|
if (!req.result.objectStoreNames.contains(CONFIG_IDB_STORE)) {
|
|
req.result.createObjectStore(CONFIG_IDB_STORE);
|
|
}
|
|
};
|
|
req.onsuccess = function () {
|
|
resolve(req.result);
|
|
};
|
|
req.onerror = function () {
|
|
reject(req.error);
|
|
};
|
|
});
|
|
}
|
|
|
|
function writeCachedAppConfigToIdb(payload) {
|
|
openConfigIdb()
|
|
.then(function (db) {
|
|
return new Promise(function (resolve, reject) {
|
|
const tx = db.transaction(CONFIG_IDB_STORE, 'readwrite');
|
|
tx.oncomplete = function () {
|
|
resolve();
|
|
};
|
|
tx.onerror = function () {
|
|
reject(tx.error);
|
|
};
|
|
tx.objectStore(CONFIG_IDB_STORE).put(payload, CONFIG_CACHE_KEY);
|
|
});
|
|
})
|
|
.catch(function (error) {
|
|
console.warn('Failed to write get_user IndexedDB cache:', error);
|
|
});
|
|
}
|
|
|
|
function readCachedAppConfigFromIdb() {
|
|
return openConfigIdb()
|
|
.then(function (db) {
|
|
return new Promise(function (resolve, reject) {
|
|
const tx = db.transaction(CONFIG_IDB_STORE, 'readonly');
|
|
const req = tx.objectStore(CONFIG_IDB_STORE).get(CONFIG_CACHE_KEY);
|
|
req.onsuccess = function () {
|
|
const value = req.result;
|
|
if (!value || typeof value !== 'object' || !value.config) {
|
|
resolve(null);
|
|
return;
|
|
}
|
|
resolve(value);
|
|
};
|
|
req.onerror = function () {
|
|
reject(req.error);
|
|
};
|
|
});
|
|
})
|
|
.catch(function () {
|
|
return null;
|
|
});
|
|
}
|
|
|
|
function clearCachedAppConfigIdb() {
|
|
openConfigIdb()
|
|
.then(function (db) {
|
|
const tx = db.transaction(CONFIG_IDB_STORE, 'readwrite');
|
|
tx.objectStore(CONFIG_IDB_STORE).delete(CONFIG_CACHE_KEY);
|
|
})
|
|
.catch(function () {
|
|
/* ignore */
|
|
});
|
|
}
|
|
|
|
function writeCachedAppConfig(config, version) {
|
|
const payload = {
|
|
cached_at: Date.now(),
|
|
version: normalizeVersion(version || getStoredAppVersion()),
|
|
domain: resolveTenantDomain(),
|
|
config: config
|
|
};
|
|
try {
|
|
localStorage.setItem(CONFIG_CACHE_KEY, JSON.stringify(payload));
|
|
clearCachedAppConfigIdb();
|
|
} catch (error) {
|
|
console.warn('get_user too large for localStorage; using IndexedDB', error);
|
|
try {
|
|
localStorage.removeItem(CONFIG_CACHE_KEY);
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
writeCachedAppConfigToIdb(payload);
|
|
}
|
|
}
|
|
|
|
async function resolveCachedPayload() {
|
|
const fromLs = readCachedAppConfigPayload();
|
|
if (fromLs) return fromLs;
|
|
return await readCachedAppConfigFromIdb();
|
|
}
|
|
|
|
function getStoredAppVersion() {
|
|
return localStorage.getItem(VERSION_STORAGE_KEY);
|
|
}
|
|
|
|
function writeStoredAppVersion(version) {
|
|
localStorage.setItem(VERSION_STORAGE_KEY, normalizeVersion(version));
|
|
}
|
|
|
|
function shouldUpdateForVersion(serverVersion) {
|
|
const normalized = normalizeVersion(serverVersion);
|
|
if (!normalized) return false;
|
|
|
|
const stored = getStoredAppVersion();
|
|
if (!stored) {
|
|
writeStoredAppVersion(normalized);
|
|
return false;
|
|
}
|
|
|
|
return stored !== normalized;
|
|
}
|
|
|
|
function canStartVersionUpdate(serverVersion) {
|
|
const version = normalizeVersion(serverVersion);
|
|
if (!version) return false;
|
|
|
|
if (sessionStorage.getItem(VERSION_LAST_RELOAD_KEY) === version) {
|
|
return false;
|
|
}
|
|
|
|
const rawLock = sessionStorage.getItem(VERSION_UPDATE_LOCK_KEY);
|
|
if (rawLock) {
|
|
try {
|
|
const lock = JSON.parse(rawLock);
|
|
const isSameVersion = lock.version === version;
|
|
const isFreshLock = Date.now() - lock.started_at < 60_000;
|
|
if (isSameVersion && isFreshLock) return false;
|
|
} catch {
|
|
sessionStorage.removeItem(VERSION_UPDATE_LOCK_KEY);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function startVersionUpdateLock(serverVersion) {
|
|
sessionStorage.setItem(
|
|
VERSION_UPDATE_LOCK_KEY,
|
|
JSON.stringify({
|
|
version: normalizeVersion(serverVersion),
|
|
started_at: Date.now()
|
|
})
|
|
);
|
|
}
|
|
|
|
function finishVersionUpdateBeforeReload(serverVersion) {
|
|
const version = normalizeVersion(serverVersion);
|
|
writeStoredAppVersion(version);
|
|
sessionStorage.setItem(VERSION_LAST_RELOAD_KEY, version);
|
|
sessionStorage.removeItem(VERSION_UPDATE_LOCK_KEY);
|
|
}
|
|
|
|
function cancelVersionUpdateLock() {
|
|
sessionStorage.removeItem(VERSION_UPDATE_LOCK_KEY);
|
|
}
|
|
|
|
function preserveAuthToken() {
|
|
return localStorage.getItem(AUTH_TOKEN_KEY);
|
|
}
|
|
|
|
function restoreAuthToken(token) {
|
|
if (token) {
|
|
localStorage.setItem(AUTH_TOKEN_KEY, token);
|
|
}
|
|
}
|
|
|
|
function clearBootstrapCachesKeepToken() {
|
|
const token = preserveAuthToken();
|
|
localStorage.removeItem(CONFIG_CACHE_KEY);
|
|
localStorage.removeItem(CONFIG_SUCCESS_URL_KEY);
|
|
localStorage.removeItem(VERSION_SUCCESS_URL_KEY);
|
|
clearCachedAppConfigIdb();
|
|
restoreAuthToken(token);
|
|
}
|
|
|
|
function hardReloadApp() {
|
|
const refreshUrl =
|
|
window.location.origin +
|
|
window.location.pathname +
|
|
'?__app_refresh=' +
|
|
Date.now() +
|
|
(window.location.hash || '');
|
|
window.location.replace(refreshUrl);
|
|
}
|
|
|
|
async function fetchJson(url, timeout) {
|
|
const controller = new AbortController();
|
|
const timeoutId = window.setTimeout(() => controller.abort(), timeout);
|
|
|
|
try {
|
|
const response = await fetch(url, {
|
|
method: 'GET',
|
|
headers: {
|
|
Accept: 'application/json'
|
|
},
|
|
cache: 'no-store',
|
|
signal: controller.signal
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Request failed: ' + response.status);
|
|
}
|
|
|
|
const contentType = response.headers.get('content-type') || '';
|
|
const text = await response.text();
|
|
const trimmed = text.trim();
|
|
|
|
if (contentType.includes('application/json') || trimmed.startsWith('{') || trimmed.startsWith('[')) {
|
|
try {
|
|
return JSON.parse(trimmed);
|
|
} catch (error) {
|
|
throw new Error('Response is not JSON. Received: ' + trimmed.substring(0, 100));
|
|
}
|
|
}
|
|
|
|
if (trimmed) {
|
|
return trimmed;
|
|
}
|
|
|
|
throw new Error('Response is empty');
|
|
} finally {
|
|
window.clearTimeout(timeoutId);
|
|
}
|
|
}
|
|
|
|
async function loadVersion(rounds) {
|
|
rounds = rounds || VERSION_RETRY_ROUNDS;
|
|
const urls = sortUrls(getVersionUrls(), VERSION_SUCCESS_URL_KEY);
|
|
|
|
for (let round = 1; round <= rounds; round++) {
|
|
for (let index = 0; index < urls.length; index++) {
|
|
const url = urls[index];
|
|
|
|
try {
|
|
const data = await fetchJson(url, VERSION_FETCH_TIMEOUT_MS);
|
|
const version = normalizeVersionResponse(data);
|
|
if (!version) {
|
|
throw new Error('Version response is empty');
|
|
}
|
|
localStorage.setItem(VERSION_SUCCESS_URL_KEY, url);
|
|
console.log('Version loaded from:', url, version);
|
|
return version;
|
|
} catch (error) {
|
|
clearStaleSuccessUrl(VERSION_SUCCESS_URL_KEY, url);
|
|
console.warn('Version failed from', url, 'round:', round, error);
|
|
}
|
|
}
|
|
}
|
|
|
|
console.warn('Version check failed from all endpoints');
|
|
return null;
|
|
}
|
|
|
|
async function fetchConfig(rounds, version) {
|
|
rounds = rounds || CONFIG_RETRY_ROUNDS;
|
|
const urls = sortUrls(getConfigUrls(), CONFIG_SUCCESS_URL_KEY);
|
|
|
|
for (let round = 1; round <= rounds; round++) {
|
|
for (let index = 0; index < urls.length; index++) {
|
|
const url = urls[index];
|
|
|
|
try {
|
|
const config = await fetchJson(url, CONFIG_FETCH_TIMEOUT_MS);
|
|
|
|
if (!config || typeof config !== 'object') {
|
|
throw new Error('Config response is invalid');
|
|
}
|
|
|
|
localStorage.setItem(CONFIG_SUCCESS_URL_KEY, url);
|
|
writeCachedAppConfig(config, version);
|
|
return { config: config, url: url };
|
|
} catch (error) {
|
|
clearStaleSuccessUrl(CONFIG_SUCCESS_URL_KEY, url);
|
|
console.warn('Config failed from', url, 'round:', round, error);
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new Error('Cannot load config from any server');
|
|
}
|
|
|
|
function applyConfig(config) {
|
|
if (isServerUnreachable(config)) {
|
|
showServerUnavailable();
|
|
throw new Error('خطا در برقراری ارتباط با سرور');
|
|
}
|
|
|
|
window.__APP_CONFIG__ = config || {};
|
|
window.__CONFIG_READY__ = true;
|
|
|
|
if (config && config.user && config.user.name_fa) {
|
|
document.title = 'پنل مدیریت ' + '-' + config.user.name_fa;
|
|
}
|
|
|
|
if (config && config.user && config.user.avatar) {
|
|
const faviconUrl = config.user.avatar;
|
|
const existingIcons = document.querySelectorAll('link[rel*="icon"]');
|
|
existingIcons.forEach((icon) => icon.remove());
|
|
|
|
const link = document.createElement('link');
|
|
link.rel = 'icon';
|
|
link.type = 'image/png';
|
|
link.href = faviconUrl + '?v=' + Date.now();
|
|
document.head.appendChild(link);
|
|
}
|
|
}
|
|
|
|
function isServerUnreachable(config) {
|
|
if (!config || typeof config !== 'object') return false;
|
|
if (config.server_reachable === false) return true;
|
|
if (config.user && config.user.server_reachable === false) return true;
|
|
return false;
|
|
}
|
|
|
|
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;">' +
|
|
'<div style="width:min(420px,100%);text-align:center;border:1px solid rgba(15,23,42,0.08);border-radius:24px;padding:28px 22px;">' +
|
|
'<div style="font-size:42px;margin-bottom:12px;">⚠️</div>' +
|
|
'<h2 style="margin:0 0 12px;font-size:20px;">خطا در برقراری ارتباط با سرور</h2>' +
|
|
'<p style="margin:0 0 20px;color:rgba(15,23,42,0.62);line-height:2;font-size:14px;">برقراری ارتباط با سرور امکانپذیر نیست. لطفاً اتصال اینترنت خود را بررسی کرده و صفحه را تازهسازی نمایید.</p>' +
|
|
'<button type="button" onclick="location.reload()" style="padding:11px 22px;border:0;border-radius:12px;background:#2563eb;color:#fff;cursor:pointer;font-weight:700;">تازهسازی صفحه</button>' +
|
|
'</div></div>';
|
|
}
|
|
|
|
function finishConfigLoad(config, error) {
|
|
if (configResolve) {
|
|
configResolve(config);
|
|
}
|
|
|
|
if (error) {
|
|
window.dispatchEvent(new CustomEvent('configError', { detail: error }));
|
|
} else {
|
|
window.dispatchEvent(new CustomEvent('configReady', { detail: config }));
|
|
}
|
|
|
|
if (configTimeoutId) {
|
|
clearTimeout(configTimeoutId);
|
|
configTimeoutId = null;
|
|
}
|
|
|
|
loadMainScript();
|
|
}
|
|
|
|
async function applyVersionUpdate(serverVersion) {
|
|
startVersionUpdateLock(serverVersion);
|
|
|
|
try {
|
|
const { config } = await fetchConfig(undefined, serverVersion);
|
|
if (isServerUnreachable(config)) {
|
|
writeCachedAppConfig(config, serverVersion);
|
|
showServerUnavailable();
|
|
cancelVersionUpdateLock();
|
|
return true;
|
|
}
|
|
clearBootstrapCachesKeepToken();
|
|
writeCachedAppConfig(config, serverVersion);
|
|
applyConfig(config);
|
|
finishVersionUpdateBeforeReload(serverVersion);
|
|
console.log('App version changed — hard refresh', serverVersion);
|
|
hardReloadApp();
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Version update failed:', error);
|
|
cancelVersionUpdateLock();
|
|
// بعد از bump نسخه (مثلاً قفل سوپر) کش قدیمی reachable را قبول نکن
|
|
showServerUnavailable();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
async function loadConfig() {
|
|
let versionChanged = false;
|
|
let needsFreshForVersion = false;
|
|
|
|
try {
|
|
const cachedPayload = await resolveCachedPayload();
|
|
const cachedConfig = cachedPayload && cachedPayload.config ? cachedPayload.config : null;
|
|
if (cachedConfig && isServerUnreachable(cachedConfig)) {
|
|
showServerUnavailable();
|
|
return;
|
|
}
|
|
|
|
const remoteVersion = await loadVersion();
|
|
needsFreshForVersion = Boolean(remoteVersion && shouldUpdateForVersion(remoteVersion));
|
|
versionChanged = Boolean(
|
|
needsFreshForVersion && canStartVersionUpdate(remoteVersion)
|
|
);
|
|
|
|
if (versionChanged) {
|
|
const updating = await applyVersionUpdate(remoteVersion);
|
|
if (updating) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
const domain = resolveTenantDomain();
|
|
if (
|
|
!needsFreshForVersion &&
|
|
isFreshGetUserCache(cachedPayload, remoteVersion, domain)
|
|
) {
|
|
applyConfig(cachedPayload.config);
|
|
if (remoteVersion) {
|
|
writeStoredAppVersion(remoteVersion);
|
|
}
|
|
console.log('Config loaded from cache; get_user skipped');
|
|
finishConfigLoad(cachedPayload.config);
|
|
return;
|
|
}
|
|
|
|
const { config, url } = await fetchConfig(undefined, remoteVersion);
|
|
applyConfig(config);
|
|
writeCachedAppConfig(config, remoteVersion);
|
|
if (remoteVersion) {
|
|
writeStoredAppVersion(remoteVersion);
|
|
}
|
|
console.log('Config loaded successfully from', url, config);
|
|
finishConfigLoad(config);
|
|
} catch (error) {
|
|
if (error && String(error.message || '').includes('خطا در برقراری ارتباط با سرور')) {
|
|
showServerUnavailable();
|
|
return;
|
|
}
|
|
console.warn('Config loader: Could not fetch config from any endpoint');
|
|
console.warn('Error details:', error && error.message ? error.message : error);
|
|
|
|
if (versionChanged || needsFreshForVersion) {
|
|
showServerUnavailable();
|
|
return;
|
|
}
|
|
|
|
const cachedPayload = await resolveCachedPayload();
|
|
const cachedConfig = cachedPayload && cachedPayload.config ? cachedPayload.config : null;
|
|
if (cachedConfig) {
|
|
try {
|
|
applyConfig(cachedConfig);
|
|
finishConfigLoad(cachedConfig, error);
|
|
return;
|
|
} catch (blockedError) {
|
|
showServerUnavailable();
|
|
return;
|
|
}
|
|
}
|
|
|
|
showServerUnavailable();
|
|
}
|
|
}
|
|
|
|
function loadMainScript() {
|
|
if (mainScriptLoaded || document.querySelector('script[src="/src/main.ts"]')) {
|
|
return;
|
|
}
|
|
|
|
mainScriptLoaded = true;
|
|
|
|
import('/src/main.ts').then(() => {
|
|
console.log('Main script loaded and executed');
|
|
});
|
|
}
|
|
|
|
configTimeoutId = setTimeout(function() {
|
|
if (!mainScriptLoaded) {
|
|
console.warn('Config loader: Timeout reached.');
|
|
const cachedConfig = readCachedAppConfig();
|
|
if (isServerUnreachable(cachedConfig) || isServerUnreachable(window.__APP_CONFIG__)) {
|
|
showServerUnavailable();
|
|
return;
|
|
}
|
|
showServerUnavailable();
|
|
}
|
|
}, CONFIG_TIMEOUT);
|
|
|
|
loadConfig();
|
|
})();
|