authorgravatar for me@t3.ggTheo Browne <me@t3.gg> 2026-09-25 20:28:35-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-25 20:28:35-07:00
logb2577d6eface9589d120bdc53e4ec0431b1e9331
tree5f3e0ba189380ac58b62c85aaf1ff5bc131e3ff0
parentb6eefc926ae305f4cb85cca797668b010cee1136
signature Signed by PGP key B5690EEEBB952194

fix(client): slow servers finish loading the thread list instead of loading it twice (#13683)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

3 files changed, 16 insertions(+), 9 deletions(-)

packages/client-runtime/src/state/session.ts+2-2
...@@ -30,8 +30,8 @@ function initialConfigOption<E>(...@@ -30,8 +30,8 @@ function initialConfigOption<E>(
30 );30 );
31}31}
3232
33// Bounded like the snapshot fetches: a wedged environment must not pin the33// Bounded so a wedged environment cannot pin the permissions check (and with it
34// permissions check (and with it the settings UI) in a loading state for long.34// the settings UI) in a loading state for long.
35const DEFAULT_SESSION_STATE_TIMEOUT_MS = 6_000;35const DEFAULT_SESSION_STATE_TIMEOUT_MS = 6_000;
3636
37/**37/**
packages/client-runtime/src/state/shellSnapshotHttp.ts+7-3
...@@ -12,9 +12,13 @@ import { environmentEndpointUrl } from "../environment/endpoint.ts";...@@ -12,9 +12,13 @@ import { environmentEndpointUrl } from "../environment/endpoint.ts";
12import { ManagedRelayDpopSigner } from "../relay/managedRelay.ts";12import { ManagedRelayDpopSigner } from "../relay/managedRelay.ts";
13import { executeAuthenticatedEnvironmentHttpRequest } from "./environmentHttpAuth.ts";13import { executeAuthenticatedEnvironmentHttpRequest } from "./environmentHttpAuth.ts";
1414
15// Bounded so a pathologically slow endpoint cannot block the (cheaper) socket15// Long enough for a slow but alive server to finish. On timeout the socket asks
16// fallback for long. The cached shell renders while this runs.16// the same server for the same full snapshot, so a short deadline only throws
17const DEFAULT_SHELL_SNAPSHOT_TIMEOUT_MS = 6_000;17// the first build away. The socket fallback is for setups where /api fails but
18// /ws works, such as a proxy that blocks /api. A dead server is caught by the
19// socket ping, which drops the session and interrupts this load. The cached
20// shell renders while this runs.
21const DEFAULT_SHELL_SNAPSHOT_TIMEOUT_MS = 20_000;
1822
19/**23/**
20 * Load the environment shell snapshot (projects + thread shells) over HTTP24 * Load the environment shell snapshot (projects + thread shells) over HTTP
packages/client-runtime/src/state/threadSnapshotHttp.ts+7-4
...@@ -13,10 +13,13 @@ import { ManagedRelayDpopSigner } from "../relay/managedRelay.ts";...@@ -13,10 +13,13 @@ import { ManagedRelayDpopSigner } from "../relay/managedRelay.ts";
13import type { RemoteEnvironmentRequestError } from "../rpc/http.ts";13import type { RemoteEnvironmentRequestError } from "../rpc/http.ts";
14import { executeAuthenticatedEnvironmentHttpRequest } from "./environmentHttpAuth.ts";14import { executeAuthenticatedEnvironmentHttpRequest } from "./environmentHttpAuth.ts";
1515
16// Bounded so a pathologically slow endpoint cannot block the (cheaper) socket16// Long enough for a slow but alive server to finish. On a cold open a timeout
17// fallback for long. The cached thread renders while this runs, so the wait only17// makes the socket ask the same server for the same snapshot again, and older
18// delays the transition to live data on the first open, not the initial paint.18// turn pages have no fallback, so a short deadline only drops work. The socket
19const DEFAULT_THREAD_SNAPSHOT_TIMEOUT_MS = 6_000;19// fallback is for setups where /api fails but /ws works, such as a proxy that
20// blocks /api. A dead server drops the socket session, which interrupts a
21// cold-open load. Older turn pages wait for this deadline.
22const DEFAULT_THREAD_SNAPSHOT_TIMEOUT_MS = 20_000;
2023
21/**24/**
22 * Load a thread's detail snapshot over HTTP instead of embedding it in the25 * Load a thread's detail snapshot over HTTP instead of embedding it in the