Symptom
On a slow or flaky network, the app can sit with no live events — no session status, no streaming, stale list — for up to ~30 seconds after launch, even though the server is reachable. In the worst case (a metadata request that hangs until timeout), the event stream doesn't start until two unrelated requests have given up.
Cause
loadConnections() in src/stores/connections.ts builds the API client, then awaits project.current() and path.get() before committing the client to the store:
client = built.client
// ...
const [proj, paths] = await Promise.all([
client.project.current().catch(() => null),
client.path.get().catch(() => null),
])
// ...
set({ ..., client, currentProject: proj, serverHome: home, ... })
Everything downstream of startup keys off client appearing in the store — app/_layout.tsx starts the SSE stream and the catalog load in an effect watching client. So the entire live pipeline is serialized behind two metadata requests that it doesn't need: neither the project name nor the server's home path is required to stream events. Each request is capped at REQUEST_TIMEOUT_MS (30s), so a hanging response delays live events by up to that long — on exactly the networks where prompt (re)connection matters most.
This is separate from #186 (dead-stream detection): #186 covers a stream that dies after starting; this covers the stream never being asked to start.
Fix
Commit the client to the store immediately after building it, then let the metadata fetch fill in currentProject/serverHome behind it — guarded so a stale response can't clobber state after the user switches servers mid-fetch. Fix included in #182.
Symptom
On a slow or flaky network, the app can sit with no live events — no session status, no streaming, stale list — for up to ~30 seconds after launch, even though the server is reachable. In the worst case (a metadata request that hangs until timeout), the event stream doesn't start until two unrelated requests have given up.
Cause
loadConnections()insrc/stores/connections.tsbuilds the API client, then awaitsproject.current()andpath.get()before committing the client to the store:Everything downstream of startup keys off
clientappearing in the store —app/_layout.tsxstarts the SSE stream and the catalog load in an effect watchingclient. So the entire live pipeline is serialized behind two metadata requests that it doesn't need: neither the project name nor the server's home path is required to stream events. Each request is capped atREQUEST_TIMEOUT_MS(30s), so a hanging response delays live events by up to that long — on exactly the networks where prompt (re)connection matters most.This is separate from #186 (dead-stream detection): #186 covers a stream that dies after starting; this covers the stream never being asked to start.
Fix
Commit the client to the store immediately after building it, then let the metadata fetch fill in
currentProject/serverHomebehind it — guarded so a stale response can't clobber state after the user switches servers mid-fetch. Fix included in #182.