Skip to main content

Local File System Access

The desktop app provides full access to your local file system with secure path validation.

File Operations

All file operations are exposed through a secure IPC bridge (electron/preload/index.ts:4):
const result = await window.electron.fs.readFile('/path/to/file.txt');

if (result.success) {
  console.log('Content:', result.data);
} else {
  console.error('Error:', result.error);
}

File Watching

Monitor directories for changes using the built-in file watcher:
// Start watching a directory
await window.electron.fs.watchDirectory('/path/to/project');

// Listen for file events
const unsubscribe = window.electron.fs.onFileEvent((event) => {
  console.log('File event:', event.type, event.path);
  
  // Event types: 'add', 'change', 'delete', 'addDir', 'deleteDir'
});

// Stop watching when done
await window.electron.fs.unwatchDirectory('/path/to/project');
unsubscribe();
Implementation: electron/main/ipc/file-system.ts:173

Security & Path Safety

All file operations validate paths to prevent access to sensitive system directories:
Allowed:
  • User home directory
  • Documents folder
  • Desktop
  • Custom project directories
  • Removable drives
Path validation uses realpath to resolve symlinks and prevent directory traversal attacks (electron/main/ipc/file-system.ts:15).

Native Dialogs

Access system file picker dialogs for a native user experience:

Open File Dialog

const result = await window.electron.dialog.showOpenDialog({
  title: 'Select a file',
  properties: ['openFile', 'multiSelections'],
  filters: [
    { name: 'Text Files', extensions: ['txt', 'md'] },
    { name: 'Code Files', extensions: ['js', 'ts', 'jsx', 'tsx'] },
    { name: 'All Files', extensions: ['*'] }
  ]
});

if (!result.canceled) {
  console.log('Selected files:', result.filePaths);
}

Save File Dialog

const result = await window.electron.dialog.showSaveDialog({
  title: 'Save file as',
  defaultPath: 'untitled.txt',
  filters: [
    { name: 'Text Files', extensions: ['txt'] },
    { name: 'All Files', extensions: ['*'] }
  ]
});

if (!result.canceled) {
  console.log('Save path:', result.filePath);
}
Implementation: electron/main/ipc/dialog.ts

Window Management

Control the application window programmatically:
await window.electron.window.minimize();
Implementation: electron/main/ipc/window.ts

Window Configuration

The main window is created with these settings (electron/main/window-manager.ts:18):
new BrowserWindow({
  width: Math.floor(width * 0.8),
  height: Math.floor(height * 0.8),
  minWidth: 1024,
  minHeight: 768,
  show: false,
  backgroundColor: '#0a0a0a',
  icon: path.join(__dirname, '../resources/icons/icon.png'),
  webPreferences: {
    preload: path.join(__dirname, '../preload/index.js'),
    contextIsolation: true,
    nodeIntegration: false,
    sandbox: false,
    webSecurity: true,
    allowRunningInsecureContent: false,
    devTools: isDev
  }
});

System Notifications

Send native system notifications:
await window.electron.notification.show({
  title: 'Build Complete',
  body: 'Your project has been built successfully!'
});
Notifications appear in the system notification center (Windows Action Center, macOS Notification Center, or Linux notification daemon). Implementation: electron/main/ipc/notification.ts

Auto-Update System

The desktop app includes automatic update functionality powered by electron-updater.

Update Flow

1

Check for Updates

App checks for updates on startup (after 3 seconds) and periodically in the background.
await window.electron.updater.checkForUpdates();
2

Update Available

When an update is found, a notification is sent to the renderer:
window.electron.updater.onUpdateAvailable((info) => {
  console.log('New version available:', info.version);
});
3

Download Update

User can choose to download the update:
await window.electron.updater.downloadUpdate();
Progress events are emitted during download:
window.electron.updater.onDownloadProgress((progress) => {
  console.log(`Downloaded: ${progress.percent}%`);
});
4

Install Update

Once downloaded, prompt user to restart and install:
window.electron.updater.onUpdateDownloaded(() => {
  // Show install prompt
});

// User confirms
await window.electron.updater.installUpdate();

Update Configuration

Auto-updater settings (electron/main/auto-updater.ts:6):
autoUpdater.logger = log;
autoUpdater.autoDownload = false;  // Manual download
autoUpdater.autoInstallOnAppQuit = true;  // Install on exit
Updates are published to GitHub Releases (electron-builder.yml:55):
publish:
  provider: github
  owner: Jackson57279
  repo: polaris

External URL Handling

Open URLs in the system’s default browser:
await window.electron.external.openUrl('https://docs.polaris-ide.com');
This is useful for:
  • Opening documentation links
  • OAuth authentication flows
  • GitHub repository links
  • External resources
Implementation: electron/main/ipc/external-url.ts

OAuth Integration

The window manager handles OAuth flows by opening provider URLs in the system browser (electron/main/window-manager.ts:59):
// OAuth providers opened externally
const isOAuthProvider =
  parsedUrl.hostname === 'github.com' ||
  parsedUrl.hostname.endsWith('.github.com') ||
  parsedUrl.hostname === 'accounts.google.com' ||
  parsedUrl.hostname.endsWith('.google.com');

if (isOAuthProvider) {
  shell.openExternal(url);
}
The app provides a native menu bar with common actions:
  • New Project (Cmd/Ctrl+N)
  • Open Project (Cmd/Ctrl+O)
  • Save (Cmd/Ctrl+S)
  • Save All (Cmd/Ctrl+Shift+S)
  • Close Project (Cmd/Ctrl+W)
  • Quit (Cmd/Ctrl+Q)
Listen for menu actions in your app:
window.electron.menu.onNewProject(() => {
  // Handle new project creation
});
Implementation: electron/main/menu.ts

Server Management

The desktop app runs a standalone Next.js server for the IDE interface.

Development Mode

In development, connects to the Next.js dev server:
// Uses port 3000 by default (configurable via NEXT_DEV_PORT)
const port = parseInt(process.env.NEXT_DEV_PORT || '3000', 10);

Production Mode

In production, spawns a standalone Next.js server:
// Finds available port (3000-3100)
const port = await getPort({ port: portRange });

// Starts server from bundled files
const serverPath = path.join(process.resourcesPath, 'server', 'server.js');
spawn('node', [serverPath], {
  env: {
    PORT: port.toString(),
    NODE_ENV: 'production',
    IS_ELECTRON: 'true'
  }
});
Implementation: electron/main/server-manager.ts:16

Health Checks

The server manager verifies the server is ready before opening windows:
private checkHealth(port: number): Promise<void> {
  return new Promise((resolve, reject) => {
    const req = http.get(`http://localhost:${port}/api/health`, (res) => {
      if (res.statusCode === 200) {
        resolve();
      } else {
        reject(new Error(`Health check failed with status: ${res.statusCode}`));
      }
    });
    
    req.setTimeout(1000);
  });
}

Single Instance Lock

Only one instance of the app can run at a time. When a second instance is launched, it focuses the existing window:
const gotTheLock = app.requestSingleInstanceLock();

if (!gotTheLock) {
  app.quit();
} else {
  app.on('second-instance', () => {
    // Focus existing window
    if (mainWindow.isMinimized()) mainWindow.restore();
    mainWindow.focus();
  });
}
Implementation: electron/main/index.ts:50

Logging

The desktop app uses electron-log for comprehensive logging:
import log from 'electron-log';

log.info('Application started');
log.error('Error:', error);
log.warn('Warning:', message);
Log locations:
  • Windows: %USERPROFILE%\AppData\Roaming\Polaris IDE\logs\main.log
  • macOS: ~/Library/Logs/Polaris IDE/main.log
  • Linux: ~/.config/Polaris IDE/logs/main.log

Offline Capabilities

While most features require internet connectivity, some operations work offline:
  • Code editing
  • File system operations
  • Syntax highlighting
  • Local file search
  • Editor preferences
  • AI features (suggestions, chat, quick edit)
  • Project synchronization with Convex
  • GitHub import/export
  • Authentication
  • Auto-updates

Performance Optimizations

The desktop app includes several performance enhancements:
  • Standalone Next.js server reduces overhead compared to full Next.js dev server
  • Direct file system access eliminates WebContainer overhead
  • Native rendering via Chromium provides excellent performance
  • Process isolation keeps main process responsive during heavy operations
  • Lazy loading defers IPC handler registration until needed

TypeScript Types

The Electron API is fully typed for TypeScript projects:
// Generated types available at window.electron
import type { ElectronAPI } from '@/electron/preload/types';

declare global {
  interface Window {
    electron: ElectronAPI;
  }
}
Type definitions: electron/preload/types.ts

Next Steps

GitHub Integration

Import and export projects to GitHub

Stack Auth

Learn about desktop authentication

Build docs developers (and LLMs) love