fix(desktop): boot relay-paired default hosts without the recovery wall
The startup path probed a relay host's stored direct URL — often the pairing creator's own loopback — and any failure landed on the Remote Server Unreachable screen before the renderer's relay restore could run. A relay-capable default host now boots to main on the local substrate for any failed direct probe (unreachable, wrong-service, incompatible), skips the 10s second probe, and lets the renderer's existing restore pick direct-or-relay.
This commit is contained in:
@@ -28,6 +28,8 @@ All notable changes to this project will be documented in this file.
|
|||||||
- Mobile: narrowing a browser window past phone size switches into the mobile layout (and back when widened); the old/new mobile layout setting is gone.
|
- Mobile: narrowing a browser window past phone size switches into the mobile layout (and back when widened); the old/new mobile layout setting is gone.
|
||||||
- Browser: an agent opening a page with the browser tool no longer pops the browser panel open (or switches the surface you're on) — the page loads in the background and the rail is where you peek at it.
|
- Browser: an agent opening a page with the browser tool no longer pops the browser panel open (or switches the surface you're on) — the page loads in the background and the rail is where you peek at it.
|
||||||
- Usage: the Command Code tile is gone — their official API exposes no usage data, so the tile could only fail.
|
- Usage: the Command Code tile is gone — their official API exposes no usage data, so the tile could only fail.
|
||||||
|
- Desktop: a relay-paired default host no longer greets every restart with the "Remote Server Unreachable" screen — the stored direct address (often the pairing machine's own loopback) failing its probe now boots the app normally and connects over the relay, picking the direct route back up automatically when it answers again.
|
||||||
|
- Mobile: on Android browsers the composer now stays above the keyboard in the chat too — the keyboard could cover it with no way to scroll it into view; the draft screen's viewport pinning now covers the chat screen on Android.
|
||||||
- Auth: an expired OpenChamber login is announced within seconds by a banner with a Log in button, instead of being discovered through failing actions. Sending pauses until login, and a conversation that failed to load reloads itself afterwards.
|
- Auth: an expired OpenChamber login is announced within seconds by a banner with a Log in button, instead of being discovered through failing actions. Sending pauses until login, and a conversation that failed to load reloads itself afterwards.
|
||||||
- Chat: a failed send returns your typed prompt to the input — whatever the reason — instead of losing it to an error toast; a mid-send session switch lands it in that session's draft.
|
- Chat: a failed send returns your typed prompt to the input — whatever the reason — instead of losing it to an error toast; a mid-send session switch lands it in that session's draft.
|
||||||
- Chat: opening a session or resizing panels could strand the view in a large empty space below the last message; the list now returns to the real end, and a width resize keeps a reader who was at the bottom at the bottom.
|
- Chat: opening a session or resizing panels could strand the view in a large empty space below the last message; the list now returns to the real end, and a width resize keeps a reader who was at the bottom at the bottom.
|
||||||
|
|||||||
@@ -1770,6 +1770,15 @@ const computeBootOutcome = ({ envTargetUrl, probe, config, localAvailable }) =>
|
|||||||
: probe?.status === 'wrong-service'
|
: probe?.status === 'wrong-service'
|
||||||
? 'wrong-service'
|
? 'wrong-service'
|
||||||
: 'ok';
|
: 'ok';
|
||||||
|
// A relay-capable host is not a recovery case just because its stored
|
||||||
|
// direct URL failed the http probe — that URL is often the pairing
|
||||||
|
// creator's own loopback (unreachable here, or worse, someone else's
|
||||||
|
// service). The relay leg is activated in the renderer's relay restore,
|
||||||
|
// which cannot run from a recovery screen: boot to main on the local
|
||||||
|
// substrate and let it pick direct-or-relay.
|
||||||
|
if (status !== 'ok' && sanitizeHostRelayForStorage(host.relay)) {
|
||||||
|
return { target: 'remote', status: 'ok', hostId: host.id, url: host.apiUrl || host.url, ...availability };
|
||||||
|
}
|
||||||
return { target: 'remote', status, hostId: host.id, url: host.apiUrl || host.url, ...availability };
|
return { target: 'remote', status, hostId: host.id, url: host.apiUrl || host.url, ...availability };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3025,12 +3034,24 @@ const resolveInitialUrl = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultHostRelayCapable = Boolean(
|
||||||
|
config.defaultHostId
|
||||||
|
&& config.defaultHostId !== LOCAL_HOST_ID
|
||||||
|
&& sanitizeHostRelayForStorage(config.hosts.find((entry) => entry.id === config.defaultHostId)?.relay),
|
||||||
|
);
|
||||||
if (apiBaseUrl && apiBaseUrl !== localUrl) {
|
if (apiBaseUrl && apiBaseUrl !== localUrl) {
|
||||||
remoteProbe = await probeHostWithTimeout(apiBaseUrl, 2_000, clientToken, requestHeaders);
|
remoteProbe = await probeHostWithTimeout(apiBaseUrl, 2_000, clientToken, requestHeaders);
|
||||||
if (remoteProbe.status === 'unreachable') {
|
if (remoteProbe.status === 'unreachable' && !defaultHostRelayCapable) {
|
||||||
remoteProbe = await probeHostWithTimeout(apiBaseUrl, 10_000, clientToken, requestHeaders);
|
remoteProbe = await probeHostWithTimeout(apiBaseUrl, 10_000, clientToken, requestHeaders);
|
||||||
}
|
}
|
||||||
if (remoteProbe.status === 'unreachable') {
|
// The renderer's relay restore owns transport selection for relay-capable
|
||||||
|
// hosts; any failed direct probe falls back to the local substrate.
|
||||||
|
if (remoteProbe.status !== 'ok' && defaultHostRelayCapable) {
|
||||||
|
apiBaseUrl = localUrl || '';
|
||||||
|
clientToken = localUrl ? readDesktopLocalClientToken() : '';
|
||||||
|
requestHeaders = {};
|
||||||
|
initialUrl = localUiUrl;
|
||||||
|
} else if (remoteProbe.status === 'unreachable') {
|
||||||
state.unreachableHosts.add(apiBaseUrl);
|
state.unreachableHosts.add(apiBaseUrl);
|
||||||
apiBaseUrl = localUrl || '';
|
apiBaseUrl = localUrl || '';
|
||||||
clientToken = localUrl ? readDesktopLocalClientToken() : '';
|
clientToken = localUrl ? readDesktopLocalClientToken() : '';
|
||||||
|
|||||||
Reference in New Issue
Block a user