Repository navigation
fix(dashboard): honour the live WebSocket port the handshake reports (#11331) - #11388
Conversation
/api/v1/ws?handshake=1 returns live.port - the port the live server is actually listening on, straight from LIVE_WS_PORT. useLiveDashboard read live.publicUrl and live.path out of that response and ignored live.port, so it kept the port compiled into the bundle. NEXT_PUBLIC_* is inlined at build time, which is exactly why the handshake exists: a prebuilt Docker or npm image has no other way to learn the runtime value. Setting LIVE_WS_PORT therefore moved the server and left the dashboard dialling 20132, with no way to correct it short of rebuilding the image - the Combo Studio banner in cheaper-inference#11331. Read the port from the handshake as well, and resolve the URL through one function in shared/utils/wsPath.ts: an explicit wsUrl wins, then a complete publicUrl, then the default with whatever port and path the handshake reported. A port outside 1..65535 is ignored rather than producing an unconnectable URL. Also collapsed the if/else in getDefaultWsUrl whose two branches returned the same expression.
|
Looked into the 3 failing checks on this PR (as of commit 913a51e):
Everything else is green: all 4 unit test shards, Vitest fast-path, "No new ESLint warnings", Docs Gates, semgrep x2, merge integrity, change classification. The fix itself ( Per the base-red convention in |
|
Thanks — added I ran the gate locally to pin down which file trips it, because the mechanism is slightly different from inherited drift. That file is not in this diff — it arrives with the base tip itself:
The other two are cancellations rather than failures — confirmed from the job API: Everything this PR actually changes is green. |
|
The three red lanes here are not this diff.
This PR touches four files —
Happy to rebase once the two guardrails files are split or baselined, if you'd rather see the lane green before merging. |
) Validado em lote combinado (batch-0824g, junto de #11388/#11397/#11415/#11418) contra o tip de release/v3.8.50: typecheck:core limpo, file-size/changelog/complexity/cognitive-complexity OK, 62/62 testes focados passando. Diagnóstico correto e bem documentado: a falha do nightly Node 26 era um teste que sorteia um número e depende do resultado, não uma quebra de compatibilidade. Comportamento de produção inalterado (a janela de jitter continua aleatória; só o teste ganhou controle sobre ela). Obrigado pela investigação detalhada!
f93fecd
into
cheaper-inference:release/v3.8.50
…rom wsPath.ts; add glm-5.3-max to the GLM test table Two more release/v3.8.51 base-reds (cheaper-inference#11449), both mechanical once traced: - src/shared/utils/wsPath.ts: cheaper-inference#11388 (merged 2026-08-24) fixed cheaper-inference#11331 by adding sanitizeLiveWsPort() + resolveLiveWsUrl() and wiring them into useLiveDashboard.ts with tests/unit/live-ws-url-11331.test.ts. The next day's cheaper-inference#11434 merge carried a competing cheaper-inference#11331 fix (resolveLiveWsPublicUrl) and its wsPath.ts version overwrote cheaper-inference#11388's hunk, while the hook and the test kept importing the two functions. Result on the tip: TS2305 in the hook, the unit test red, and the Turbopack build failing on "Export resolveLiveWsUrl doesn't exist". This re-adds cheaper-inference#11388's two functions verbatim next to the surviving resolveLiveWsPublicUrl; the names do not collide and the precedence they implement (explicit wsUrl → handshake publicUrl → default URL with handshake port/path) is unchanged. - open-sse/mcp-server/__tests__/glmCodingProviderConfig.test.ts: the registry ships glm-5.3-max with a "max" effort tier. Z.AI's GLM-5.3 reference lists reasoning_effort ∈ {low, high, max} and recommends max for coding, so the registry is right and the inventory/tier tables in the test were stale (they already declared ["low","high","max"] on the base model). Verification: tests/unit/live-ws-url-11331.test.ts 11/11; glmCodingProviderConfig 10/10; tsc reports no errors in useLiveDashboard.ts / wsPath.ts.
#11484) Validated in a combined sub-batch worktree off release/v3.8.51 tip. Its second commit reimplemented wsPath.ts's sanitizeLiveWsPort/resolveLiveWsUrl to fix a build break it hit — that exact break is already fixed on the current tip via #11502 (the original #11388 implementation restored verbatim). Conflicted against that; resolved by keeping the tip's established implementation and dropping the redundant reimplementation (both are functionally equivalent; the tip's carries the original #11331 doc comments and precedence contract). Pushed the same resolution to this branch. - typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK - Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff - Focused test: cli-settings-jcode.test.ts (integration) — part of sub-batch's 165/165 run Thanks for the real end-to-end verification (production server, real ~/.jcode/config.toml, jcode --provider-profile omniroute serving a completion, jcode provider-doctor passing) — the managed-block approach (marker-delimited, preserves user-authored config, 409s instead of corrupting on a hand-written conflicting table) is exactly the right shape for this integration.
cheaper-inference#11484) Validated in a combined sub-batch worktree off release/v3.8.51 tip. Its second commit reimplemented wsPath.ts's sanitizeLiveWsPort/resolveLiveWsUrl to fix a build break it hit — that exact break is already fixed on the current tip via cheaper-inference#11502 (the original cheaper-inference#11388 implementation restored verbatim). Conflicted against that; resolved by keeping the tip's established implementation and dropping the redundant reimplementation (both are functionally equivalent; the tip's carries the original cheaper-inference#11331 doc comments and precedence contract). Pushed the same resolution to this branch. - typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity — all OK - Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff - Focused test: cli-settings-jcode.test.ts (integration) — part of sub-batch's 165/165 run Thanks for the real end-to-end verification (production server, real ~/.jcode/config.toml, jcode --provider-profile omniroute serving a completion, jcode provider-doctor passing) — the managed-block approach (marker-delimited, preserves user-authored config, 409s instead of corrupting on a hand-written conflicting table) is exactly the right shape for this integration.
…aper-inference#11380) Validado em lote combinado (batch-0824g, junto de cheaper-inference#11388/cheaper-inference#11397/cheaper-inference#11415/cheaper-inference#11418) contra o tip de release/v3.8.50: typecheck:core limpo, file-size/changelog/complexity/cognitive-complexity OK, 62/62 testes focados passando. Diagnóstico correto e bem documentado: a falha do nightly Node 26 era um teste que sorteia um número e depende do resultado, não uma quebra de compatibilidade. Comportamento de produção inalterado (a janela de jitter continua aleatória; só o teste ganhou controle sobre ela). Obrigado pela investigação detalhada!
…heaper-inference#11331) (cheaper-inference#11388) Validado em lote combinado (batch-0824g) contra o tip de release/v3.8.50: typecheck:core limpo, gates estáticos OK, 62/62 testes focados passando (incluindo tests/unit/live-ws-url-11331.test.ts, 11 casos + mutation-check). Resolve o incidente real do cheaper-inference#11331: o handshake já reportava a porta live real, mas o cliente descartava esse campo e ficava preso na porta compilada no bundle. Precedência clara (wsUrl explícito > publicUrl completo > porta/path do handshake aplicados ao default). Obrigado pela contribuição!
Fixes #11331 (the part that is a bug).
The handshake already reports the port; the client throws it away
/api/v1/ws?handshake=1returns the live server's real listening port:useLiveDashboardreadspublicUrlandpathout of that response — and nothing else:so the URL keeps the port compiled into the bundle:
NEXT_PUBLIC_*is inlined at build time — which is the whole reason this handshake exists, as the comment right above it says. A prebuilt Docker or npm image has no other way to learn a runtime value. So settingLIVE_WS_PORTmoves the server and leaves the dashboard dialling 20132, with no way to correct it short of rebuilding the image. That is theLive disabled — WebSocket disconnectedbanner in the report.The change
Read
live.portfrom the handshake too, and resolve the URL in one place (shared/utils/wsPath.ts):wsUrlfrom the callerlive.publicUrlfrom the handshakeA port outside 1..65535 is ignored rather than producing an unconnectable URL.
Also collapsed the
if/elseingetDefaultWsUrlwhose two branches returned the same expression — it read as a distinction that no longer exists.Scope — what this does not do
The report also asks the frontend to infer the proxy topology and connect over the origin port with a path prefix. That is already supported through
LIVE_WS_PUBLIC_URL, which the handshake surfaces aslive.publicUrland which this PR keeps as the highest-priority source. Guessing a same-origin upgrade instead would break the documented setup, sincesrc/proxy.tshas no upgrade handler on the HTTP port — that is the reason for the "Bug #1 fix" comment this PR preserved. So the fix here is the unambiguous half: a configured port must not be ignored.Tests
tests/unit/live-ws-url-11331.test.ts— 11 cases:0,70000,1.5,"","abc",null,NaN,{}→ ignoredpublicUrlwins over the reported port; an explicitwsUrlwins over everythingderiveLiveWsPathbehaviour unchangedMutation-checked — dropping the
url.portassignment turns 2 red:tsc --noEmitreports nothing in the touched files; prettier/eslint pre-commit hooks clean.