(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 = '
برقراری ارتباط با سرور امکانپذیر نیست. لطفاً اتصال اینترنت خود را بررسی کرده و صفحه را تازهسازی نمایید.
' + '' + '