[eric] browser: recover a card that opens straight onto a JSON URL (initial-load path + homepage fallback)

This commit is contained in:
ciregenz
2026-07-16 10:37:32 -07:00
parent 6bec61eda4
commit f7472b3dbf
2 changed files with 25 additions and 6 deletions
@@ -53,7 +53,7 @@ import {
import { setLastInteractedBrowser } from '@/shared/browserFocus';
import BrowserFindBar from './BrowserFindBar';
import { useBrowserActivity } from '@/shared/useBrowserActivity';
import { getActionLabel } from '@/shared/browserCommandHandler';
import { getActionLabel, readDataDocument, recoverCardOffDataWall } from '@/shared/browserCommandHandler';
import { resolveInput, isGoogleSearch } from '@/shared/resolveUrl';
import BrowserAgentOverlay from './BrowserAgentOverlay';
import { useOverlayScrollPassthrough } from '../hooks/interaction/useOverlayScrollPassthrough';
@@ -313,7 +313,14 @@ const BrowserCard: React.FC<Props> = ({
const doLoad = () => {
// Reaching dom-ready proves the webview survived Chromium's commit phase (the historical Windows mount segfault). Clear the crash-safety marker.
if (isWindows) markWindowsWebviewSurvived();
wv.loadURL(targetUrl).catch(() => {});
wv.loadURL(targetUrl)
.then(async () => {
// If this card's own entry URL is a raw JSON/API endpoint, it paints an unreadable data
// wall; get it onto a real page. (The agent-navigate path is handled in handleNavigate;
// this covers the initial load, which never goes through the command handler.)
if (await readDataDocument(wv)) recoverCardOffDataWall(wv, targetUrl);
})
.catch(() => {});
try {
(wv as any).setVisualZoomLevelLimits?.(1, 1);
(wv as any).setZoomFactor?.(1);
+16 -4
View File
@@ -332,7 +332,8 @@ async function handleNavigate(wv: BrowserWebview, params: Record<string, any>):
// Chromium renders any JSON (or JSON-shaped text) response with its built-in viewer, so a navigate
// to an API endpoint leaves the card showing a wall of raw data. contentType is the reliable tell;
// re-fetch same-origin (the just-loaded GET, idempotent) to hand the agent the exact bytes.
async function readDataDocument(wv: BrowserWebview): Promise<{ contentType: string; body: string } | null> {
// Exported so BrowserCard can reuse the exact same detection for the card's own initial load.
export async function readDataDocument(wv: BrowserWebview): Promise<{ contentType: string; body: string } | null> {
const code = `(async () => {
const ct = String(document.contentType || '').toLowerCase();
const isJson = ct.startsWith('application/json');
@@ -356,14 +357,25 @@ async function readDataDocument(wv: BrowserWebview): Promise<{ contentType: stri
// Get the card off a raw-data wall: step back to the real page the agent came from, or, if it opened
// straight onto the data URL, fall back to the site homepage. Fire-and-forget, the agent already has
// the data; this is purely so a human sees a page instead of JSON.
function recoverCardOffDataWall(wv: BrowserWebview, dataUrl: string): void {
// the data; this is purely so a human sees a page instead of JSON. Exported for BrowserCard's own-load path.
export function recoverCardOffDataWall(wv: BrowserWebview, dataUrl: string): void {
let origin = '';
try { origin = new URL(dataUrl).origin; } catch { /* keep '' */ }
try {
if (wv.canGoBack()) {
wv.goBack();
// A card that opened STRAIGHT onto the data URL has only the webview's blank initial entry
// behind it, so goBack lands on about:blank. Detect that and fall back to the site homepage
// so the card shows a real page rather than a blank one.
window.setTimeout(() => {
try {
const u = wv.getURL();
if ((!u || u === 'about:blank') && origin) void wv.loadURL(origin).catch(() => {});
} catch { /* leave as-is */ }
}, 400);
return;
}
void wv.loadURL(new URL(dataUrl).origin).catch(() => {});
if (origin) void wv.loadURL(origin).catch(() => {});
} catch {
/* leave the card as-is if recovery fails; the data still reached the agent */
}