Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions emain/emain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,19 @@ electron.ipcMain.on("quicklook", (event, filePath: string) => {
}
});

electron.ipcMain.handle("clear-webview-storage", async (event, webContentsId: number) => {
try {
const wc = electron.webContents.fromId(webContentsId);
if (wc && wc.session) {
await wc.session.clearStorageData();
console.log("Cleared cookies and storage for webContentsId:", webContentsId);
}
} catch (e) {
console.error("Failed to clear cookies and storage:", e);
throw e;
}
});
Comment on lines +376 to +387
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Validate webContentsId parameter.

The handler doesn't validate the webContentsId parameter before using it. If a malformed or negative value is passed, electron.webContents.fromId() will return undefined, but the code should explicitly validate the input.

Consider adding parameter validation:

 electron.ipcMain.handle("clear-webview-storage", async (event, webContentsId: number) => {
     try {
+        if (!webContentsId || typeof webContentsId !== 'number' || webContentsId <= 0) {
+            throw new Error("Invalid webContentsId");
+        }
         const wc = electron.webContents.fromId(webContentsId);
         if (wc && wc.session) {
             await wc.session.clearStorageData();
             console.log("Cleared cookies and storage for webContentsId:", webContentsId);
+        } else {
+            console.warn("WebContents not found for webContentsId:", webContentsId);
         }
     } catch (e) {
         console.error("Failed to clear cookies and storage:", e);
         throw e;
     }
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
electron.ipcMain.handle("clear-webview-storage", async (event, webContentsId: number) => {
try {
const wc = electron.webContents.fromId(webContentsId);
if (wc && wc.session) {
await wc.session.clearStorageData();
console.log("Cleared cookies and storage for webContentsId:", webContentsId);
}
} catch (e) {
console.error("Failed to clear cookies and storage:", e);
throw e;
}
});
electron.ipcMain.handle("clear-webview-storage", async (event, webContentsId: number) => {
try {
if (!webContentsId || typeof webContentsId !== 'number' || webContentsId <= 0) {
throw new Error("Invalid webContentsId");
}
const wc = electron.webContents.fromId(webContentsId);
if (wc && wc.session) {
await wc.session.clearStorageData();
console.log("Cleared cookies and storage for webContentsId:", webContentsId);
} else {
console.warn("WebContents not found for webContentsId:", webContentsId);
}
} catch (e) {
console.error("Failed to clear cookies and storage:", e);
throw e;
}
});
🤖 Prompt for AI Agents
In emain/emain.ts around lines 372 to 383, the IPC handler uses webContentsId
without validating it; add explicit parameter validation (ensure webContentsId
is a number, finite, and a positive integer) before calling
electron.webContents.fromId(), and return or throw a descriptive error when
validation fails; after validating, continue to resolve the webContents and
check wc exists and has a session before clearing storage, and include brief
error messages when validation or lookup fails so malformed or negative values
are handled safely.


electron.ipcMain.on("open-native-path", (event, filePath: string) => {
console.log("open-native-path", filePath);
filePath = filePath.replace("~", electronApp.getPath("home"));
Expand Down
1 change: 1 addition & 0 deletions emain/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ contextBridge.exposeInMainWorld("api", {
openNativePath: (filePath: string) => ipcRenderer.send("open-native-path", filePath),
captureScreenshot: (rect: Rectangle) => ipcRenderer.invoke("capture-screenshot", rect),
setKeyboardChordMode: () => ipcRenderer.send("set-keyboard-chord-mode"),
clearWebviewStorage: (webContentsId: number) => ipcRenderer.invoke("clear-webview-storage", webContentsId),
setWaveAIOpen: (isOpen: boolean) => ipcRenderer.send("set-waveai-open", isOpen),
});

Expand Down
38 changes: 34 additions & 4 deletions frontend/app/view/webview/webview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -411,19 +411,19 @@ export class WebViewModel implements ViewModel {
const searchTemplate = globalStore.get(defaultSearchAtom);
const nextUrl = this.ensureUrlScheme(newUrl, searchTemplate);
console.log("webview loadUrlPromise", reason, nextUrl, "cur=", this.webviewRef.current?.getURL());

if (!this.webviewRef.current) {
return Promise.reject(new Error("WebView ref not available"));
}

if (newUrl != nextUrl) {
globalStore.set(this.url, nextUrl);
}

if (this.webviewRef.current.getURL() != nextUrl) {
return this.webviewRef.current.loadURL(nextUrl);
}

return Promise.resolve();
}

Expand Down Expand Up @@ -495,6 +495,25 @@ export class WebViewModel implements ViewModel {
}
}

clearHistory() {
try {
this.webviewRef.current?.clearHistory();
} catch (e) {
console.error("Failed to clear history", e);
}
}

async clearCookiesAndStorage() {
try {
const webContentsId = this.webviewRef.current?.getWebContentsId();
if (webContentsId) {
await getApi().clearWebviewStorage(webContentsId);
}
} catch (e) {
console.error("Failed to clear cookies and storage", e);
}
}
Comment on lines +506 to +515
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add user feedback for clearCookiesAndStorage operation.

The clearCookiesAndStorage() method clears storage for the current webview instance but the menu label says "All Web Widgets". This creates a discrepancy between the UI text and the actual behavior. Additionally, users receive no feedback when the operation completes or fails.

Consider one of these solutions:

Option 1: Update the menu label to reflect the actual behavior:

-                label: "Clear Cookies and Storage (All Web Widgets)",
+                label: "Clear Cookies and Storage (This Widget)",

Option 2: If clearing all web widgets is intended, you'll need to iterate over all webview instances and clear each one's storage. In that case, you should also add user feedback:

async clearCookiesAndStorage() {
    try {
        const webContentsId = this.webviewRef.current?.getWebContentsId();
        if (webContentsId) {
            await getApi().clearWebviewStorage(webContentsId);
            // Add success notification
            console.log("Successfully cleared cookies and storage");
        }
    } catch (e) {
        console.error("Failed to clear cookies and storage", e);
        // Consider showing user-facing error notification
    }
}
🤖 Prompt for AI Agents
frontend/app/view/webview/webview.tsx lines 506-515: the clearCookiesAndStorage
method behavior (clears current webview only) mismatches the menu label "All Web
Widgets" and provides no user feedback; either change the menu label to indicate
it only clears the current widget, or implement the intended "clear all"
behavior by enumerating all webview instances (or retrieving all webContentsIds
from the managing component/state) and calling getApi().clearWebviewStorage for
each id, awaiting all operations and collecting errors, then surface a
user-facing notification on success (e.g., "Cleared cookies and storage for N
widgets") and show an error notification if any failures occur while still
attempting to clear others; ensure console.error remains for debug logging.


keyDownHandler(e: WaveKeyboardEvent): boolean {
if (checkKeyPressed(e, "Cmd:l")) {
this.urlInputRef?.current?.focus();
Expand Down Expand Up @@ -619,6 +638,17 @@ export class WebViewModel implements ViewModel {
}
},
},
{
type: "separator",
},
{
label: "Clear History",
click: () => this.clearHistory(),
},
{
label: "Clear Cookies and Storage (All Web Widgets)",
click: () => fireAndForget(() => this.clearCookiesAndStorage()),
},
Comment on lines +641 to +651
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Verify clearCookiesAndStorage scope matches label.

The menu label states "Clear Cookies and Storage (All Web Widgets)" but the implementation only clears storage for the current webview instance (via this.webviewRef.current?.getWebContentsId()). This is inconsistent.

Please clarify the intended behavior:

  • If it should clear only the current widget, update the label to remove "(All Web Widgets)"
  • If it should clear all widgets, the implementation needs to be modified to iterate over all webview instances

Related to the comment on lines 506-515.

];
}
}
Expand Down
1 change: 1 addition & 0 deletions frontend/types/custom.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ declare global {
openNativePath(filePath: string): void; // open-native-path
captureScreenshot(rect: Electron.Rectangle): Promise<string>; // capture-screenshot
setKeyboardChordMode: () => void; // set-keyboard-chord-mode
clearWebviewStorage: (webContentsId: number) => Promise<void>; // clear-webview-storage
setWaveAIOpen: (isOpen: boolean) => void; // set-waveai-open
};

Expand Down
Loading