fix(browser): park webviews permanently paintable

Delete the renderer capture prep handshake and keep screenshots on the serialized invalidate/retry path. The capture harness now defaults to the production P1 attach-off parking check.
This commit is contained in:
Mohamed Boudra
2026-07-03 11:34:48 +02:00
parent cc21262130
commit ab62a023fd
15 changed files with 358 additions and 1652 deletions
-135
View File
@@ -1,117 +1,6 @@
import { contextBridge, ipcRenderer, webUtils } from "electron";
type EventHandler = (payload: unknown) => void;
type BrowserPixelCapturePrepareHandler = (input: {
requestId: string;
browserId: string;
}) => Promise<{ token: string }>;
type BrowserPixelCaptureRestoreHandler = (input: { token: string }) => Promise<void>;
type BrowserPixelCaptureCancelHandler = (input: {
requestId?: string;
token?: string;
}) => Promise<void>;
let prepareForPixelCaptureHandler: BrowserPixelCapturePrepareHandler | null = null;
let restorePixelCaptureHandler: BrowserPixelCaptureRestoreHandler | null = null;
let cancelPixelCaptureHandler: BrowserPixelCaptureCancelHandler | null = null;
const canceledPixelCaptureRequestIds = new Set<string>();
function readStringField(payload: unknown, key: string): string | null {
if (!isRecord(payload)) {
return null;
}
const value = payload[key];
return typeof value === "string" && value.length > 0 ? value : null;
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function errorMessage(error: unknown): string {
return error instanceof Error ? error.message : String(error);
}
ipcRenderer.on("paseo:browser:capture-prepare", async (_event, payload: unknown) => {
const requestId = readStringField(payload, "requestId");
const browserId = readStringField(payload, "browserId");
if (!requestId || !browserId || !prepareForPixelCaptureHandler) {
ipcRenderer.send("paseo:browser:capture-prepared", {
requestId: requestId ?? "unknown",
ok: false,
message: "Browser pixel capture preparation is unavailable.",
});
return;
}
try {
const preparation = await prepareForPixelCaptureHandler({ requestId, browserId });
if (canceledPixelCaptureRequestIds.delete(requestId)) {
await restorePixelCaptureHandler?.({ token: preparation.token });
ipcRenderer.send("paseo:browser:capture-prepared", {
requestId,
ok: false,
message: "Browser pixel capture preparation was canceled.",
});
return;
}
ipcRenderer.send("paseo:browser:capture-prepared", {
requestId,
ok: true,
token: preparation.token,
});
} catch (error) {
canceledPixelCaptureRequestIds.delete(requestId);
ipcRenderer.send("paseo:browser:capture-prepared", {
requestId,
ok: false,
message: errorMessage(error),
});
}
});
ipcRenderer.on("paseo:browser:capture-cancel", async (_event, payload: unknown) => {
const requestId = readStringField(payload, "requestId");
const token = readStringField(payload, "token");
if (requestId) {
canceledPixelCaptureRequestIds.add(requestId);
}
if (!requestId && !token) {
return;
}
try {
await cancelPixelCaptureHandler?.({
...(requestId ? { requestId } : {}),
...(token ? { token } : {}),
});
} catch {
// The original prepare/restore request owns the user-visible error.
}
});
ipcRenderer.on("paseo:browser:capture-restore", async (_event, payload: unknown) => {
const requestId = readStringField(payload, "requestId");
const token = readStringField(payload, "token");
if (!requestId || !token || !restorePixelCaptureHandler) {
ipcRenderer.send("paseo:browser:capture-restored", {
requestId: requestId ?? "unknown",
ok: false,
message: "Browser pixel capture restore is unavailable.",
});
return;
}
try {
await restorePixelCaptureHandler({ token });
ipcRenderer.send("paseo:browser:capture-restored", { requestId, ok: true });
} catch (error) {
ipcRenderer.send("paseo:browser:capture-restored", {
requestId,
ok: false,
message: errorMessage(error),
});
}
});
contextBridge.exposeInMainWorld("paseoDesktop", {
platform: process.platform,
@@ -201,29 +90,5 @@ contextBridge.exposeInMainWorld("paseoDesktop", {
) => ipcRenderer.invoke("paseo:browser:capture-element", browserId, rect),
copyElement: (payload: { text?: string; imageDataUrl?: string }) =>
ipcRenderer.invoke("paseo:browser:copy-element", payload),
onPrepareForPixelCapture: (handler: BrowserPixelCapturePrepareHandler): (() => void) => {
prepareForPixelCaptureHandler = handler;
return () => {
if (prepareForPixelCaptureHandler === handler) {
prepareForPixelCaptureHandler = null;
}
};
},
onRestorePixelCapture: (handler: BrowserPixelCaptureRestoreHandler): (() => void) => {
restorePixelCaptureHandler = handler;
return () => {
if (restorePixelCaptureHandler === handler) {
restorePixelCaptureHandler = null;
}
};
},
onCancelPixelCapture: (handler: BrowserPixelCaptureCancelHandler): (() => void) => {
cancelPixelCaptureHandler = handler;
return () => {
if (cancelPixelCaptureHandler === handler) {
cancelPixelCaptureHandler = null;
}
};
},
},
});