(force?: boolean)
| 35 | * @param force - Skip cache and fetch fresh data |
| 36 | */ |
| 37 | export async function checkForUpdate(force?: boolean): Promise<UpdateCheckResult> { |
| 38 | const config = readConfig(); |
| 39 | const now = Date.now(); |
| 40 | |
| 41 | if (!force && config.lastUpdateCheck && config.latestVersion) { |
| 42 | const lastCheck = new Date(config.lastUpdateCheck).getTime(); |
| 43 | if (now - lastCheck < CHECK_INTERVAL_MS) { |
| 44 | return { |
| 45 | current: VERSION, |
| 46 | latest: config.latestVersion, |
| 47 | updateAvailable: isNewerSemver(config.latestVersion, VERSION), |
| 48 | }; |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | try { |
| 53 | const controller = new AbortController(); |
| 54 | const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS); |
| 55 | const res = await fetch(NPM_REGISTRY_URL, { |
| 56 | signal: controller.signal, |
| 57 | headers: { Connection: "close" }, |
| 58 | }); |
| 59 | clearTimeout(timeout); |
| 60 | |
| 61 | if (!res.ok) return fallbackResult(config.latestVersion); |
| 62 | |
| 63 | const data = (await res.json()) as { version?: string }; |
| 64 | const latest = data.version ?? VERSION; |
| 65 | |
| 66 | config.lastUpdateCheck = new Date().toISOString(); |
| 67 | config.latestVersion = latest; |
| 68 | writeConfig(config); |
| 69 | |
| 70 | return { current: VERSION, latest, updateAvailable: isNewerSemver(latest, VERSION) }; |
| 71 | } catch { |
| 72 | return fallbackResult(config.latestVersion); |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | function fallbackResult(cachedLatest?: string): UpdateCheckResult { |
| 77 | return { |
no test coverage detected