diff --git a/muxplex/frontend/terminal.js b/muxplex/frontend/terminal.js index e285e57..f10158d 100644 --- a/muxplex/frontend/terminal.js +++ b/muxplex/frontend/terminal.js @@ -165,7 +165,15 @@ function connectWebSocket(name, remoteId) { // response (plus an 800ms settle delay for ttyd to bind its port). The early return // prevents falling through to the direct _connectWebSocket() call below. if (_reconnectAttempts >= 2 && _currentSession) { - fetch('/api/sessions/' + encodeURIComponent(_currentSession) + '/connect', { + var connectPath; + if (remoteId) { + // Remote session: route through federation proxy + connectPath = '/api/federation/' + encodeURIComponent(remoteId) + '/connect/' + encodeURIComponent(_currentSession); + } else { + // Local session + connectPath = '/api/sessions/' + encodeURIComponent(_currentSession) + '/connect'; + } + fetch(connectPath, { method: 'POST', headers: { 'Content-Type': 'application/json' }, }) diff --git a/muxplex/frontend/tests/test_terminal.mjs b/muxplex/frontend/tests/test_terminal.mjs index bd628bc..fc0c391 100644 --- a/muxplex/frontend/tests/test_terminal.mjs +++ b/muxplex/frontend/tests/test_terminal.mjs @@ -1012,4 +1012,27 @@ test('terminal.js Ctrl+Shift+V handler calls preventDefault to suppress double p ); }); +// --- Federation reconnect routing --- + +test('terminal.js reconnect uses federation connect path for remote sessions', () => { + // Regression: connect() inside connectWebSocket() always called local + // /api/sessions/{name}/connect even when remoteId was set, causing 404 for remote sessions. + const source = fs.readFileSync(new URL('../terminal.js', import.meta.url), 'utf8'); + + // Find the connect() function inside connectWebSocket + const connectFnIdx = source.indexOf('function connect()'); + assert.ok(connectFnIdx !== -1, 'must have a connect() function inside connectWebSocket'); + // Extract enough chars to cover the full reconnect block (incl. long comment preamble) + const connectFn = source.substring(connectFnIdx, connectFnIdx + 1000); + + assert.ok( + connectFn.includes('remoteId'), + 'reconnect connect() must check remoteId to choose federation vs local routing', + ); + assert.ok( + connectFn.includes('/api/federation/'), + 'reconnect connect() must use /api/federation/{remoteId}/connect/{name} for remote sessions', + ); +}); +