fix(browser): let the newest input or extension gesture decide who set an extension call off

This commit is contained in:
Kelvin Amoaba
2026-11-14 01:14:07 +00:00
parent 01e09c3f7d
commit 937fb58406
2 changed files with 24 additions and 18 deletions
@@ -22,19 +22,21 @@ export function noteBrowserExtensionUserGesture(
recentGestures.set(signal, Date.now())
}
export function hasBrowserExtensionUserGesture(caller: BrowserExtensionCaller): boolean {
if (caller.userGesture === true) {
return true
}
/** When Orca last handed the caller's extension a gesture, if still within the gesture window. */
export function getBrowserExtensionUserGestureAt(caller: BrowserExtensionCaller): number | null {
const state = getHostSessionState(caller.session)
if (!state) {
return false
return null
}
const signal = getBrowserExtensionContextSignal(state, caller.extension.id)
const at = recentGestures.get(signal)
return (
at !== undefined &&
return at !== undefined &&
!signal.aborted &&
Date.now() - at <= BROWSER_EXTENSION_USER_GESTURE_WINDOW_MS
)
? at
: null
}
export function hasBrowserExtensionUserGesture(caller: BrowserExtensionCaller): boolean {
return caller.userGesture === true || getBrowserExtensionUserGestureAt(caller) !== null
}
@@ -3,7 +3,7 @@ import { getLastBrowserGuestInputInSession } from '../../guest-lifecycle/input/b
import type { BrowserExtensionCaller } from '../api-runtime/browser-extension-namespace-registry'
import {
BROWSER_EXTENSION_USER_GESTURE_WINDOW_MS,
hasBrowserExtensionUserGesture
getBrowserExtensionUserGestureAt
} from '../permissions/browser-extension-user-gesture'
import type { openBrowserExtensionTab } from './browser-extension-tab-model'
@@ -19,24 +19,28 @@ function pageOfGuest(guestWebContentsId: number): AgentPage {
/**
* The agent's page this call acts for, or null when the user set it off. An extension reacts to
* its profile's pages (a wallet popup, an OAuth tab) without saying which input started it, so
* the latest click or key in the profile decides, then whether an agent is driving a page there.
* the newest recent click, key or Orca-delivered gesture decides, then whether an agent leads.
*/
export function findBrowserExtensionCallerAgentPage(
caller: BrowserExtensionCaller
): AgentPage | null {
// Why first: an agent's click on an extension page also counts as that page's user gesture.
if (caller.webContents && browserManager.isAgentLeadingGuest(caller.webContents.id)) {
return pageOfGuest(caller.webContents.id)
}
if (hasBrowserExtensionUserGesture(caller)) {
const now = Date.now()
const lastInput = getLastBrowserGuestInputInSession(caller.session)
const input =
lastInput && now - lastInput.at <= BROWSER_EXTENSION_USER_GESTURE_WINDOW_MS ? lastInput : null
const gestureAt = getBrowserExtensionUserGestureAt(caller)
if (gestureAt !== null && (!input || gestureAt >= input.at)) {
return null
}
const input = getLastBrowserGuestInputInSession(caller.session)
if (input && Date.now() - input.at <= BROWSER_EXTENSION_USER_GESTURE_WINDOW_MS) {
if (input) {
// Agents and remote viewers send injected input; only the desktop user's own may surface.
return input.byAgent ? pageOfGuest(input.guestWebContentsId) : null
}
return browserManager.findAgentPageInSession(caller.session)
// Why before userGesture: an agent's click on an extension page also activates that page.
if (caller.webContents && browserManager.isAgentLeadingGuest(caller.webContents.id)) {
return pageOfGuest(caller.webContents.id)
}
return caller.userGesture ? null : browserManager.findAgentPageInSession(caller.session)
}
/** An agent's extension tab opens in the background beside its page, never in the user's view. */