(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 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 = 5; const CONFIG_RETRY_ROUNDS = 5; const CONFIG_TIMEOUT = 12000; let configTimeoutId; let mainScriptLoaded = false; function getProtocol() { return window.location.protocol === 'https:' ? 'https:' : 'http:'; } function getVersionUrls() { const protocol = getProtocol(); return [ 'https://nerkh.gold/get_version', 'https://tablo.talasevin.ir/get_version', 'https://abshode-service.montgit.ir/server/get_version', protocol + '//212.23.201.173:8381/get_version', protocol + '//91.212.174.137:4040/server/get_version' ]; } function getConfigUrls() { const protocol = getProtocol(); return [ protocol + '//nerkh.gold/get_user', 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' ]; } 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 readCachedAppConfig() { 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.config; } catch (error) { console.warn('Failed to read cached get_user:', error); localStorage.removeItem(CONFIG_CACHE_KEY); return null; } } function writeCachedAppConfig(config) { try { localStorage.setItem( CONFIG_CACHE_KEY, JSON.stringify({ cached_at: Date.now(), config: config }) ); } catch (error) { console.warn('Failed to write get_user cache:', error); } } 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); 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') || ''; if (!contentType.includes('application/json')) { const text = await response.text(); throw new Error('Response is not JSON. Received: ' + text.substring(0, 100)); } return await response.json(); } 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]; const timeout = index === urls.length - 1 ? 6000 : 3500; try { const data = await fetchJson(url, timeout); 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) { 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]; const timeout = index === urls.length - 1 ? 7000 : 4000; try { const config = await fetchJson(url, timeout); if (!config || typeof config !== 'object') { throw new Error('Config response is invalid'); } localStorage.setItem(CONFIG_SUCCESS_URL_KEY, url); writeCachedAppConfig(config); 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) { 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 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(); clearBootstrapCachesKeepToken(); writeCachedAppConfig(config); applyConfig(config); finishVersionUpdateBeforeReload(serverVersion); console.log('App version changed — hard refresh', serverVersion); hardReloadApp(); return true; } catch (error) { console.error('Version update failed:', error); cancelVersionUpdateLock(); return false; } } async function loadConfig() { try { // ۱) کش get_user — اگر بود سریع اعمال شود const cachedConfig = readCachedAppConfig(); if (cachedConfig) { applyConfig(cachedConfig); console.log('Applied cached get_user'); } // ۲) get_version — اگر تغییر کرده hard refresh const remoteVersion = await loadVersion(); if (remoteVersion && shouldUpdateForVersion(remoteVersion) && canStartVersionUpdate(remoteVersion)) { const updating = await applyVersionUpdate(remoteVersion); if (updating) { return; } } // ۳) تازه کردن get_user و کش const { config, url } = await fetchConfig(); applyConfig(config); console.log('Config loaded successfully from', url, config); finishConfigLoad(config); } catch (error) { 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.'); const cachedConfig = readCachedAppConfig(); if (cachedConfig) { applyConfig(cachedConfig); finishConfigLoad(cachedConfig, error); return; } window.__APP_CONFIG__ = {}; window.__CONFIG_READY__ = true; finishConfigLoad({}, error); } } 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. Loading main.ts with empty/cached config.'); const cachedConfig = readCachedAppConfig(); window.__APP_CONFIG__ = cachedConfig || window.__APP_CONFIG__ || {}; window.__CONFIG_READY__ = true; if (configResolve) { configResolve(window.__APP_CONFIG__); } loadMainScript(); } }, CONFIG_TIMEOUT); loadConfig(); })();