From e8ce18dcb70ac7fe931c90f8c01d9223f2197828 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Jul 2026 12:05:47 +0000 Subject: [PATCH] Migrate Tier 1 renderer files off direct process reads via preload bridge --- .../Settings/Core/EmbeddedCoreSettings.tsx | 3 +- src/App/Settings/Style/BackgroundPicker.tsx | 3 +- src/main/preload.js | 7 +++ src/shared/lib/appMenu.ts | 11 +++-- src/shared/lib/nexusEnv.ts | 48 +++++++++++++++++++ src/shared/lib/store.tsx | 3 +- src/shared/lib/wallet.ts | 3 +- 7 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 src/shared/lib/nexusEnv.ts diff --git a/src/App/Settings/Core/EmbeddedCoreSettings.tsx b/src/App/Settings/Core/EmbeddedCoreSettings.tsx index 17071b30b..2916cf0a4 100644 --- a/src/App/Settings/Core/EmbeddedCoreSettings.tsx +++ b/src/App/Settings/Core/EmbeddedCoreSettings.tsx @@ -8,6 +8,7 @@ import Button from 'components/Button'; import Switch from 'components/Switch'; import { TextField } from 'components/TextField'; import { useFieldValue } from 'lib/form'; +import nexusEnv from 'lib/nexusEnv'; import { updateSettings, settingAtoms } from 'lib/settings'; import { confirm, openErrorDialog } from 'lib/dialog'; import { restartCore, stopCore, startCore } from 'lib/core'; @@ -102,7 +103,7 @@ function CoreBinaryPathField() { title: __('Select Nexus Core binary'), properties: ['openFile'], filters: - process.platform === 'win32' + nexusEnv.platform === 'win32' ? [{ name: 'Windows executable', extensions: ['exe'] }] : undefined, }); diff --git a/src/App/Settings/Style/BackgroundPicker.tsx b/src/App/Settings/Style/BackgroundPicker.tsx index dfd629bdf..12dd8e09e 100644 --- a/src/App/Settings/Style/BackgroundPicker.tsx +++ b/src/App/Settings/Style/BackgroundPicker.tsx @@ -11,6 +11,7 @@ import { updateTheme, themeAtom, } from 'lib/theme'; +import nexusEnv from 'lib/nexusEnv'; __ = __context('Settings.Style'); @@ -27,7 +28,7 @@ async function handleFilePick() { }); let path = files?.[0]; if (path) { - if (process.platform === 'win32') { + if (nexusEnv.platform === 'win32') { path = path.replace(/\\/g, '/'); } updateTheme({ wallpaper: path }); diff --git a/src/main/preload.js b/src/main/preload.js index be1b6bdbd..6202b1e4b 100644 --- a/src/main/preload.js +++ b/src/main/preload.js @@ -104,6 +104,13 @@ function exposeInMainWorld(name, api) { exposeInMainWorld('nexusEnv', { NODE_ENV: process.env.NODE_ENV || 'production', PORT: process.env.PORT || '', + // Exposed so renderer code can branch on OS without needing direct access + // to the `process` global, which is unavailable when contextIsolation is + // enabled and nodeIntegration is disabled. + platform: process.platform, + arch: process.arch, + HOME: process.env.HOME || '', + USERPROFILE: process.env.USERPROFILE || '', }); exposeInMainWorld('nexusElectron', { diff --git a/src/shared/lib/appMenu.ts b/src/shared/lib/appMenu.ts index a75531af6..2da88e801 100644 --- a/src/shared/lib/appMenu.ts +++ b/src/shared/lib/appMenu.ts @@ -28,6 +28,7 @@ import { } from 'lib/coreInfo'; // import { confirm } from 'lib/dialog'; import { walletDataDir } from 'consts/paths'; +import nexusEnv, { isDevelopment } from 'lib/nexusEnv'; import { checkForUpdates, quitAndInstall, updaterStateAtom } from 'lib/updater'; import AboutModal from 'components/AboutModal'; @@ -340,9 +341,9 @@ function buildDarwinTemplate() { label: __('View'), submenu: [menuItems.reloadUI, menuItems.toggleFullScreen], }; - if (process.env.NODE_ENV === 'development' || devMode) { + if (isDevelopment || devMode) { subMenuWindow.submenu.push(menuItems.toggleDevTools); - if (process.env.NODE_ENV === 'development') { + if (isDevelopment) { subMenuWindow.submenu.push(menuItems.toggleJotaiDevTools); subMenuWindow.submenu.push(menuItems.toggleReactQueryDevTools); } @@ -417,9 +418,9 @@ function buildDefaultTemplate() { label: __('View'), submenu: [menuItems.reloadUI, menuItems.toggleFullScreen], }; - if (process.env.NODE_ENV === 'development' || devMode) { + if (isDevelopment || devMode) { subMenuView.submenu.push(menuItems.separator, menuItems.toggleDevTools); - if (process.env.NODE_ENV === 'development') { + if (isDevelopment) { subMenuView.submenu.push(menuItems.toggleJotaiDevTools); subMenuView.submenu.push(menuItems.toggleReactQueryDevTools); } @@ -452,7 +453,7 @@ function buildDefaultTemplate() { */ function buildMenu() { const template = - process.platform === 'darwin' + nexusEnv.platform === 'darwin' ? buildDarwinTemplate() : buildDefaultTemplate(); ipcRenderer.invoke('set-app-menu', template); diff --git a/src/shared/lib/nexusEnv.ts b/src/shared/lib/nexusEnv.ts new file mode 100644 index 000000000..4aed491c2 --- /dev/null +++ b/src/shared/lib/nexusEnv.ts @@ -0,0 +1,48 @@ +/** + * Safe accessor for `window.nexusEnv`, which is exposed by the preload + * script (see src/main/preload.js). Renderer code should read platform/env + * information through this module instead of the `process` global, since + * `process` is unavailable in the renderer's main world when + * contextIsolation is enabled and nodeIntegration is disabled. + */ +export interface NexusEnv { + /** Mirrors `process.env.NODE_ENV` from the main process. */ + NODE_ENV: string; + /** Dev server port, only meaningful when `NODE_ENV === 'development'`. */ + PORT: string; + /** Mirrors `process.platform` from the main process. */ + platform: NodeJS.Platform; + /** Mirrors `process.arch` from the main process. */ + arch: string; + /** Mirrors `process.env.HOME`; populated on macOS/Linux. */ + HOME: string; + /** Mirrors `process.env.USERPROFILE`; populated on Windows. */ + USERPROFILE: string; +} + +const fallbackNexusEnv: NexusEnv = { + NODE_ENV: 'production', + PORT: '', + platform: 'linux', + arch: '', + HOME: '', + USERPROFILE: '', +}; + +const injectedNexusEnv: NexusEnv | undefined = (window as any).nexusEnv; +if (!injectedNexusEnv) { + // window.nexusEnv should always be set by the preload script + // (src/main/preload.js). If it's missing, fall back to safe defaults but + // log loudly so the misconfiguration doesn't silently masquerade as Linux. + console.error( + 'window.nexusEnv is not available; the preload bridge may not have run. ' + + 'Falling back to default platform/env values, which may be incorrect.' + ); +} + +const nexusEnv: NexusEnv = injectedNexusEnv || fallbackNexusEnv; + +export default nexusEnv; + +export const isDevelopment = nexusEnv.NODE_ENV === 'development'; +export const platform = nexusEnv.platform; diff --git a/src/shared/lib/store.tsx b/src/shared/lib/store.tsx index 039248ad3..ac23a924b 100644 --- a/src/shared/lib/store.tsx +++ b/src/shared/lib/store.tsx @@ -12,8 +12,9 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { queryClientAtom } from 'jotai-tanstack-query'; import { rqDevToolsOpenAtom, jotaiDevToolsOpenAtom } from 'lib/ui'; import jotaiDevToolsStyles from 'jotai-devtools/styles.css'; +import { isDevelopment } from 'lib/nexusEnv'; -const isDev = process.env.NODE_ENV === 'development'; +const isDev = isDevelopment; export const store = createStore(); diff --git a/src/shared/lib/wallet.ts b/src/shared/lib/wallet.ts index a05dd5583..cd5279576 100644 --- a/src/shared/lib/wallet.ts +++ b/src/shared/lib/wallet.ts @@ -13,6 +13,7 @@ import { stopCore } from 'lib/core'; import { coreConnectedAtom } from 'lib/coreInfo'; import { logOut, loggedInAtom } from 'lib/session'; import { settingsAtom } from 'lib/settings'; +import nexusEnv from 'lib/nexusEnv'; let _navigate: NavigateFunction | null = null; export function navigate(to: To, options?: NavigateOptions) { @@ -55,7 +56,7 @@ export function prepareWallet() { const forceQuit = await ipcRenderer.invoke('is-force-quit'); if (!forceQuit) { ipcRenderer.invoke('hide-window'); - if (process.platform === 'darwin') { + if (nexusEnv.platform === 'darwin') { ipcRenderer.invoke('hide-dock'); } return;