@@ -54,6 +54,9 @@ export interface ProxyContextValue {
5454// then the latency has not been fetched yet. Calculations happen async for each proxy in the list.
5555// Refer to the returned report for a given proxy for more information.
5656proxyLatencies :ProxyLatencies ;
57+ // latenciesLoaded is true when the latencies have been initially loaded.
58+ // Once set to true, it will not be set to false again.
59+ latenciesLoaded :boolean ;
5760// refetchProxyLatencies will trigger refreshing of the proxy latencies. By default the latencies
5861// are loaded once.
5962refetchProxyLatencies :( ) => Date ;
@@ -122,8 +125,11 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
122125
123126// Every time we get a new proxiesResponse, update the latency check
124127// to each workspace proxy.
125- const { proxyLatencies, refetch :refetchProxyLatencies } =
126- useProxyLatency ( proxiesResp ) ;
128+ const {
129+ proxyLatencies,
130+ refetch :refetchProxyLatencies ,
131+ loaded :latenciesLoaded ,
132+ } = useProxyLatency ( proxiesResp ) ;
127133
128134// updateProxy is a helper function that when called will
129135// update the proxy being used.
@@ -136,7 +142,8 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
136142loadUserSelectedProxy ( ) ,
137143proxyLatencies ,
138144// Do not auto select based on latencies, as inconsistent latencies can cause this
139- // to behave poorly.
145+ // to change on each call. updateProxy should be stable when selecting a proxy to
146+ // prevent flickering.
140147false ,
141148) ,
142149) ;
@@ -149,6 +156,34 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
149156updateProxy ( ) ;
150157} , [ proxiesResp , proxyLatencies ] ) ;
151158
159+ // This useEffect will auto select the best proxy if the user has not selected one.
160+ // It must wait until all latencies are loaded to select based on latency. This does mean
161+ // the first time a user loads the page, the proxy will "flicker" to the best proxy.
162+ //
163+ // Once the page is loaded, or the user selects a proxy, this will not run again.
164+ // biome-ignore lint/correctness/useExhaustiveDependencies: Only update if the source data changes
165+ useEffect ( ( ) => {
166+ if ( loadUserSelectedProxy ( ) !== undefined ) {
167+ return ; // User has selected a proxy, do not auto select.
168+ }
169+ if ( ! latenciesLoaded ) {
170+ // Wait until the latencies are loaded first.
171+ return ;
172+ }
173+
174+ const best = getPreferredProxy (
175+ proxiesResp ?? [ ] ,
176+ loadUserSelectedProxy ( ) ,
177+ proxyLatencies ,
178+ true ,
179+ ) ;
180+
181+ if ( best ?. proxy ) {
182+ saveUserSelectedProxy ( best . proxy ) ;
183+ updateProxy ( ) ;
184+ }
185+ } , [ latenciesLoaded , proxiesResp , proxyLatencies ] ) ;
186+
152187return (
153188< ProxyContext . Provider
154189value = { {
@@ -157,6 +192,7 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
157192userProxy :userSavedProxy ,
158193proxy :proxy ,
159194proxies :proxiesResp ,
195+ latenciesLoaded :latenciesLoaded ,
160196isLoading :proxiesLoading ,
161197isFetched :proxiesFetched ,
162198error :proxiesError ,
@@ -214,12 +250,12 @@ export const getPreferredProxy = (
214250
215251// If no proxy is selected, or the selected proxy is unhealthy default to the primary proxy.
216252if ( ! selectedProxy || ! selectedProxy . healthy ) {
217- //By default, use the primary proxy.
253+ //Default to the primary proxy
218254selectedProxy = proxies . find ( ( proxy ) => proxy . name === "primary" ) ;
219255
220256// If we have latencies, then attempt to use the best proxy by latency instead.
221257const best = selectByLatency ( proxies , latencies ) ;
222- if ( autoSelectBasedOnLatency && best ) {
258+ if ( autoSelectBasedOnLatency && best !== undefined ) {
223259selectedProxy = best ;
224260}
225261}