({
isUpdating,
onChangeIsUpdating,
onAutoUpdaterResult,
autoUpdaterResult,
showSuccessMessage,
verbose
}: Props)
| 21 | verbose: boolean; |
| 22 | }; |
| 23 | export function AutoUpdater({ |
| 24 | isUpdating, |
| 25 | onChangeIsUpdating, |
| 26 | onAutoUpdaterResult, |
| 27 | autoUpdaterResult, |
| 28 | showSuccessMessage, |
| 29 | verbose |
| 30 | }: Props): React.ReactNode { |
| 31 | const [versions, setVersions] = useState<{ |
| 32 | global?: string | null; |
| 33 | latest?: string | null; |
| 34 | }>({}); |
| 35 | const [hasLocalInstall, setHasLocalInstall] = useState(false); |
| 36 | const updateSemver = useUpdateNotification(autoUpdaterResult?.version); |
| 37 | useEffect(() => { |
| 38 | void localInstallationExists().then(setHasLocalInstall); |
| 39 | }, []); |
| 40 | |
| 41 | // Track latest isUpdating value in a ref so the memoized checkForUpdates |
| 42 | // callback always sees the current value. Without this, the 30-minute |
| 43 | // interval fires with a stale closure where isUpdating is false, allowing |
| 44 | // a concurrent installGlobalPackage() to run while one is already in |
| 45 | // progress. |
| 46 | const isUpdatingRef = useRef(isUpdating); |
| 47 | isUpdatingRef.current = isUpdating; |
| 48 | const checkForUpdates = React.useCallback(async () => { |
| 49 | if (isUpdatingRef.current) { |
| 50 | return; |
| 51 | } |
| 52 | if ("production" === 'test' || "production" === 'development') { |
| 53 | logForDebugging('AutoUpdater: Skipping update check in test/dev environment'); |
| 54 | return; |
| 55 | } |
| 56 | const currentVersion = MACRO.VERSION; |
| 57 | const channel = getInitialSettings()?.autoUpdatesChannel ?? 'latest'; |
| 58 | let latestVersion = await getLatestVersion(channel); |
| 59 | const isDisabled = isAutoUpdaterDisabled(); |
| 60 | |
| 61 | // Check if max version is set (server-side kill switch for auto-updates) |
| 62 | const maxVersion = await getMaxVersion(); |
| 63 | if (maxVersion && latestVersion && gt(latestVersion, maxVersion)) { |
| 64 | logForDebugging(`AutoUpdater: maxVersion ${maxVersion} is set, capping update from ${latestVersion} to ${maxVersion}`); |
| 65 | if (gte(currentVersion, maxVersion)) { |
| 66 | logForDebugging(`AutoUpdater: current version ${currentVersion} is already at or above maxVersion ${maxVersion}, skipping update`); |
| 67 | setVersions({ |
| 68 | global: currentVersion, |
| 69 | latest: latestVersion |
| 70 | }); |
| 71 | return; |
| 72 | } |
| 73 | latestVersion = maxVersion; |
| 74 | } |
| 75 | setVersions({ |
| 76 | global: currentVersion, |
| 77 | latest: latestVersion |
| 78 | }); |
| 79 | |
| 80 | // Check if update needed and perform update |
nothing calls this directly
no test coverage detected