Nnextop / app

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.ts exposes two globals via contextBridge:
    • window.desktop — namespaced helpers (window, fs, menu) + a guarded generic ipcRenderer (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 when window.desktop is absent (e.g. rendered on the web / during SSR). Keep this pattern when extending.