const { contextBridge, ipcRenderer } = require("electron"); contextBridge.exposeInMainWorld("theseus", { navigate: (input) => ipcRenderer.invoke("navigate", input), search: (q) => ipcRenderer.invoke("search", q), newTab: () => ipcRenderer.invoke("new-tab"), closeTab: (id) => ipcRenderer.invoke("close-tab", id), switchTab: (id) => ipcRenderer.invoke("switch-tab", id), moveTab: (id, targetId, place) => ipcRenderer.invoke("move-tab", id, targetId, place), suggestAddress: (query, rect) => ipcRenderer.invoke("suggest-address", query, rect), closeAddressPicker: () => ipcRenderer.invoke("close-address-picker"), addressCursor: (dir) => ipcRenderer.invoke("address-cursor", dir), togglePwFill: (rect) => ipcRenderer.invoke("toggle-pw-fill", rect), onPwAvailability: (cb) => ipcRenderer.on("pw-availability", (_e, d) => cb(d)), // Update chip: chrome subscribes to update-available; clicking the chip's // download button opens the URL in the system browser; ✕ dismisses for // the current session. onUpdateAvailable: (cb) => ipcRenderer.on("update-available", (_e, d) => cb(d)), // Signed extension updates staged by the background check: { staged: // [{id,name,version}] }. They apply on the next launch, so the chrome // offers a restart. stagedAddons() asks once at boot. onAddonUpdates: (cb) => ipcRenderer.on("addon-updates", (_e, d) => cb(d)), stagedAddons: () => ipcRenderer.invoke("addons-list-staged"), applyStagedAddons: () => ipcRenderer.invoke("addons-apply-staged"), restartApp: () => ipcRenderer.invoke("app-restart"), openUpdateDownload: (url) => ipcRenderer.invoke("open-update-download", url), installUpdateNow: () => ipcRenderer.invoke("install-update-now"), dismissUpdate: () => ipcRenderer.invoke("dismiss-update"), goHome: () => ipcRenderer.invoke("go-home"), back: () => ipcRenderer.invoke("go-back"), forward: () => ipcRenderer.invoke("go-forward"), // Press-and-hold / right-click on Back or Forward: native menu of the // tab's history entries in that direction; picking one jumps to it. navHistoryMenu: (dir, rect) => ipcRenderer.invoke("nav-history-menu", dir, rect), reload: (hard) => ipcRenderer.invoke("reload", !!hard), stop: () => ipcRenderer.invoke("stop"), toggleTor: () => ipcRenderer.invoke("toggle-tor"), openSettings: (section) => ipcRenderer.invoke("open-settings", section), getSettings: () => ipcRenderer.invoke("settings-get"), setSetting: (key, val) => ipcRenderer.invoke("settings-set", key, val), onSettingsUpdate: (cb) => ipcRenderer.on("settings-update", (_e, d) => cb(d)), // Find-in-page. main.js fires 'find-open' on Ctrl+F; chrome renderer // owns the bar UI and drives findInPage / stopFindInPage via these // wrappers. Match count / active ordinal comes back through onFindResult. onFindOpen: (cb) => ipcRenderer.on("find-open", () => cb()), findInPage: (query, opts) => ipcRenderer.invoke("find-in-page", query, opts || {}), findStop: () => ipcRenderer.invoke("find-stop"), onFindResult: (cb) => ipcRenderer.on("find-result", (_e, d) => cb(d)), toggleSiteInfo: (rect) => ipcRenderer.invoke("toggle-site-info", rect), switchToBcnr: () => ipcRenderer.invoke("switch-to-bcnr"), setChromeHeight: (h) => ipcRenderer.invoke("set-chrome-height", h), getSearchEngines: () => ipcRenderer.invoke("search-engines"), setSearchEngine: (id) => ipcRenderer.invoke("set-search-engine", id), addEngine: (eng) => ipcRenderer.invoke("add-engine", eng), removeEngine: (id) => ipcRenderer.invoke("remove-engine", id), toggleEnginePicker: (rect) => ipcRenderer.invoke("toggle-engine-picker", rect), onEngines: (cb) => ipcRenderer.on("engines", (_e, d) => cb(d)), getBookmarks: () => ipcRenderer.invoke("bookmarks-get"), addBookmark: (bm) => ipcRenderer.invoke("bookmark-add", bm), updateBookmark: (url, patch) => ipcRenderer.invoke("bookmark-update", url, patch), removeBookmark: (url) => ipcRenderer.invoke("bookmark-remove", url), moveBookmark: (fromUrl, targetUrl, place) => ipcRenderer.invoke("bookmark-move", fromUrl, targetUrl, place), onBookmarks: (cb) => ipcRenderer.on("bookmarks", (_e, d) => cb(d)), onNav: (cb) => ipcRenderer.on("nav", (_e, d) => cb(d)), onTor: (cb) => ipcRenderer.on("tor", (_e, d) => cb(d)), onTabs: (cb) => ipcRenderer.on("tabs", (_e, d) => cb(d)), tabReload: (id) => ipcRenderer.invoke("tab-reload", id), tabDuplicate: (id) => ipcRenderer.invoke("tab-duplicate", id), tabMute: (id, on) => ipcRenderer.invoke("tab-mute", id, on), tabGroup: (id, color) => ipcRenderer.invoke("tab-group", id, color), tabGroupToggle: (color) => ipcRenderer.invoke("tab-group-toggle", color), tabBookmark: (id) => ipcRenderer.invoke("tab-bookmark", id), onAddressPicked: (cb) => ipcRenderer.on("address-picked", (_e, url) => cb(url)), onBcnrOffer: (cb) => ipcRenderer.on("bcnr-offer", (_e, d) => cb(d)), // Collision-mode (BCNR ↔ ICANN) live switcher for the active tab collisionSwitch: (arg) => ipcRenderer.invoke("collision-switch", arg), collisionState: () => ipcRenderer.invoke("collision-state"), // Downloads — the toolbar button subscribes to `downloads` to update its // badge, and toggleDownloads opens/closes the floating panel. getDownloads: () => ipcRenderer.invoke("downloads-get"), toggleDownloads: (rect) => ipcRenderer.invoke("toggle-downloads", rect), onDownloads: (cb) => ipcRenderer.on("downloads", (_e, d) => cb(d)), // Add-on sidebar: toggle, open on a specific panel, close, or subscribe // to state (visibility + which panel is active + the panel list). The // extension dock in chrome.html renders one button per panel and calls // openSidebar / closeSidebar accordingly. toggleSidebar: () => ipcRenderer.invoke("sidebar-toggle"), openSidebar: (panelId) => ipcRenderer.invoke("sidebar-open", panelId), closeSidebar: () => ipcRenderer.invoke("sidebar-close"), sidebarState: () => ipcRenderer.invoke("sidebar-state"), onSidebarState: (cb) => ipcRenderer.on("sidebar-state", (_e, d) => cb(d)), // Extension dock: drag-reorder (key = "p:" | "m:") and // the right-click menu (native; main owns the actions). dockMove: (key, targetKey, place) => ipcRenderer.invoke("dock-move", key, targetKey, place), dockMenu: (key, rect) => ipcRenderer.invoke("dock-menu", key, rect), // Toolbar-menu (dropdown from an add-on's dock icon): dispatch the picked // item id to the add-on's "menu-select" handler. addonMenuSelect: (addonId, itemId) => ipcRenderer.invoke("addon-menu-select", addonId, itemId), // Pop the dock-icon dropdown as a NATIVE menu. Renderer-side DOM popovers // get clipped by chrome.html's own WebContentsView height (CHROME_H) and // then covered by the tab view below it — a native Menu.popup escapes that // layering entirely. Pass the button's viewport-rect so main can anchor. toolbarMenuPopup: (addonId, rect) => ipcRenderer.invoke("toolbar-menu-popup", addonId, rect), tabContextMenuPopup: (tabId, rect) => ipcRenderer.invoke("tab-context-menu-popup", tabId, rect), // Ariadne's Thread menu behind the registry button at the end of the // address bar (BCDN/ICANN switch, remembered choices, policy, settings). registryMenuPopup: (rect) => ipcRenderer.invoke("registry-menu-popup", rect), // Page zoom on the active tab: step +1 / -1 along Chrome's ladder, or reset to 100 %. zoomStep: (dir) => ipcRenderer.invoke("zoom-step", dir), zoomReset: () => ipcRenderer.invoke("zoom-reset"), // Chrome listens so it can drop the "active" tint when the native menu // dismisses (Esc, outside click, item picked — main fires all three). onToolbarMenuClosed: (cb) => ipcRenderer.on("toolbar-menu-closed", () => cb()), });