From c3b47e33e16c8d2f851378ba6c23847ff044f78a Mon Sep 17 00:00:00 2001 From: adonis Date: Sat, 27 Jun 2026 11:29:56 +0330 Subject: [PATCH] fix some bugs 2 --- src/config/load-config.ts | 4 +-- src/modules/pwa/manifest.ts | 70 +++++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/config/load-config.ts b/src/config/load-config.ts index 3e29f2f..3eebce7 100644 --- a/src/config/load-config.ts +++ b/src/config/load-config.ts @@ -7,7 +7,7 @@ function getProtocol() { return window.location.protocol === 'https:' ? 'https:' : 'http:' } -function getConfigUrls() { +export function getConfigUrls() { const protocol = getProtocol() return [ @@ -19,7 +19,7 @@ function getConfigUrls() { ] } -function sortConfigUrls(urls: string[]) { +export function sortConfigUrls(urls: string[]) { const lastSuccessUrl = localStorage.getItem(CONFIG_SUCCESS_URL_KEY) return [...urls].sort((a, b) => { diff --git a/src/modules/pwa/manifest.ts b/src/modules/pwa/manifest.ts index 369f30f..65674ec 100644 --- a/src/modules/pwa/manifest.ts +++ b/src/modules/pwa/manifest.ts @@ -1,5 +1,6 @@ import type { AppConfig } from '@/config/types' import { getConfig, getRawAppConfig } from '@/config/app-config' +import { getConfigUrls, sortConfigUrls } from '@/config/load-config' import { clearCachedPwaManifest, readCachedPwaManifest, @@ -15,7 +16,6 @@ export const PWA_MANIFEST_READY_EVENT = 'pwa-manifest-ready' const CONFIG_SUCCESS_URL_KEY = 'CONFIG_Success_URL' let pendingBeforeInstallPrompt: Event | null = null let installCaptureInitialized = false -const MANIFEST_RETRY_COUNT = 5 const MANIFEST_RETRY_DELAY_MS = 500 function sleep(ms: number) { @@ -33,22 +33,21 @@ export function getConfigBaseFromStorage() { return normalizeBaseUrl(lastSuccess) } -/** یک URL — فقط monifist همان tenant/user؛ بدون fallback عمومی */ -export function resolveManifestUrl(config?: AppConfig | null) { - const raw = config ?? getRawAppConfig() - const userId = raw?.user?.id - const base = getConfigBaseFromStorage() - - if (!base) return '' +function configUrlToManifestUrl(configUrl: string) { + return `${configUrl.replace(/\/+$/, '')}/manifest.json` +} +/** همان ۵ URL پایهٔ get_user — اولویت با CONFIG_Success_URL */ +export function resolveManifestUrls(config?: AppConfig | null): string[] { const explicit = getConfig('manifest_url') - if (explicit) return explicit + if (explicit) return [explicit] -/* if (userId != null && userId !== '') { - return `${base}/get_user/${userId}/manifest.json` - }*/ + return sortConfigUrls(getConfigUrls()).map(configUrlToManifestUrl) +} - return `${base}/get_user/manifest.json` +/** اولین کاندید — برای سازگاری */ +export function resolveManifestUrl(config?: AppConfig | null) { + return resolveManifestUrls(config)[0] ?? '' } function isValidManifest(payload: unknown): payload is PwaManifest { @@ -91,28 +90,33 @@ async function fetchManifestOnce(url: string, timeout = 6000): Promise { - if (!url) { - throw new Error('No manifest URL (config base or user id missing)') +/** هر URL یک بار — مثل لوپ get_user */ +async function fetchManifestTryingUrls( + urls: string[] +): Promise<{ manifest: PwaManifest; manifestUrl: string }> { + if (!urls.length) { + throw new Error('No manifest URL candidates') } let lastError: unknown = null - for (let attempt = 1; attempt <= MANIFEST_RETRY_COUNT; attempt++) { + for (let index = 0; index < urls.length; index++) { + const url = urls[index] + try { - return await fetchManifestOnce(url) + const manifest = await fetchManifestOnce(url) + return { manifest, manifestUrl: url } } catch (error) { lastError = error - console.warn(`PWA manifest failed (${url}), attempt ${attempt}/${MANIFEST_RETRY_COUNT}`, error) + console.warn(`PWA manifest failed (${url}), candidate ${index + 1}/${urls.length}`, error) } - if (attempt < MANIFEST_RETRY_COUNT) { - await sleep(MANIFEST_RETRY_DELAY_MS * attempt) + if (index < urls.length - 1) { + await sleep(MANIFEST_RETRY_DELAY_MS) } } - throw lastError ?? new Error('PWA manifest could not be loaded') + throw lastError ?? new Error('PWA manifest could not be loaded from any server') } let manifestBlobUrl: string | null = null @@ -229,6 +233,8 @@ function resolveInstallIcons(manifest: PwaManifest) { return mapped } + + function prepareManifestForInstall(manifest: PwaManifest) { const scopeUrl = toSameOriginManifestUrl(manifest.scope ?? manifest.start_url, '/') const startUrl = toSameOriginManifestUrl(manifest.start_url, '/') @@ -482,31 +488,30 @@ async function applyCachedManifestEntry( /** * بعد از loadAppConfig / setAppConfig صدا بزن. - * get_user دوباره fetch نمی‌شود — فقط monifist.json از base کش‌شده. + * get_user دوباره fetch نمی‌شود — manifest از همان ۵ URL پایهٔ get_user امتحان می‌شود. */ export async function setupPwaManifest(config?: AppConfig | null): Promise { const raw = config ?? getRawAppConfig() const userId = raw?.user?.id const configBase = getConfigBaseFromStorage() + const manifestUrls = resolveManifestUrls(raw) - if (!configBase) { - console.warn('PWA manifest skipped: CONFIG_Success_URL not set yet') + if (!manifestUrls.length) { + console.warn('PWA manifest skipped: no manifest URL candidates') removeDynamicManifestLinks() setPwaManifestReady(false) return false } - const cached = readCachedPwaManifest(userId, configBase) + const cached = configBase ? readCachedPwaManifest(userId, configBase) : null if (cached && (await applyCachedManifestEntry(cached))) { console.info('PWA manifest applied from cache:', cached.manifest_url) return true } - const manifestUrl = resolveManifestUrl(raw) - try { - const manifest = await fetchManifestWithRetry(manifestUrl) + const { manifest, manifestUrl } = await fetchManifestTryingUrls(manifestUrls) const prepared = prepareManifestForInstall(manifest) @@ -514,10 +519,13 @@ export async function setupPwaManifest(config?: AppConfig | null): Promise