Architecture
┌─────────────────────────── Electron Main Process ───────────────────────────┐│ ││ app.whenReady() ││ ├─ new BrowserWindow({ contextIsolation, sandbox, nodeIntegration:false })││ ├─ registerNextOP(mainWindow, options) ← from "nextop-app/main" ││ │ ├─ ipcMain handlers: fs, shell, clipboard, notification, menu, ││ │ │ window controls, secure-store, store, dialog, tray, ││ │ │ global-shortcut, internal windows ││ │ └─ navigation guards (will-navigate / setWindowOpenHandler) ││ └─ startNextServer(dir, dev) → live Next.js on 127.0.0.1:<port> ││ │└───────────────▲──────────────────────────────────────────────▲─────────────┘│ contextBridge (preload.ts) │ http│ window.desktop / window.nextop │┌───────────────┴────────────────────────────────────────────────┴────────────┐│ Renderer (your Next.js app) ││ React hooks: useFs, useWindow, useMenu, useShell, useNotification, ││ useClipboard, useSecureStore, useSocket, useDialog, ││ useTray, useGlobalShortcut, useStore ││ Components: <Link> (nextop-app/link), <VirtualList> (nextop-app/...) │└──────────────────────────────────────────────────────────────────────────────┘
Renderer ↔ main bridge
preload.tsexposes two globals viacontextBridge:window.desktop— namespaced helpers (window,fs,menu) + a guarded genericipcRenderer(send/on/invoke).window.nextop—{ openExternal(url) }.
contextIsolation: true,nodeIntegration: false,sandbox: true— the correct Electron security baseline.- Hooks degrade gracefully to
null/ no-op whenwindow.desktopis absent (e.g. rendered on the web / during SSR). Keep this pattern when extending.