# How the Server Edition of nodeterm Serves the Renderer to a Browser

> Discover how nodeterm Server Edition sends its React canvas UI to browsers using HTTP, WebSocket RPC, and web-native protocols, replacing Electron IPC.

- Repository: [eneskirca/nodeterm](https://github.com/eneskirca/nodeterm)
- Tags: architecture
- Published: 2026-08-26

---

**The Server Edition of nodeterm delivers the React-based canvas UI to browsers through a lightweight HTTP server, WebSocket RPC layer, and platform shim that replaces Electron's IPC with web-native protocols while reusing the same core services.**

The Server Edition of nodeterm provides a headless backend that renders the terminal's interface directly in any modern web browser instead of wrapping it in an Electron window. Located in the `src/server/` directory of the `eneskirca/nodeterm` repository, this architecture abstracts the `CorePlatform` interface through an HTTP and WebSocket stack, eliminating Electron-specific dependencies while maintaining full compatibility with the desktop edition's file system, Git, and agent services. This implementation allows users to access the complete nodeterm experience through a standard browser without installing the desktop application.

## Static HTTP Server for Compiled Assets

The Server Edition begins with a lightweight HTTP implementation in [`src/server/http.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/http.ts) that creates an Express-style server. This server delivers the compiled front-end assets from the `out/renderer/` directory—the output of the Vite build process—as static files.

When a browser navigates to the root endpoint, the server returns [`index.html`](https://github.com/eneskirca/nodeterm/blob/main/index.html), which loads the bundled JavaScript and CSS required to boot the React-based canvas. This approach ensures the browser receives the exact same renderer code that would normally execute inside an Electron window, maintaining visual and functional parity between the desktop and web editions.

## WebSocket RPC Layer

While the HTTP server handles static assets, [`src/server/ws.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/ws.ts) establishes the real-time communication channel essential for terminal functionality. This module creates a WebSocket endpoint at `/ws` that replaces Electron's `ipcMain/ipcRenderer` communication model.

The browser connects to this endpoint through the `window.nodeTerminal` bridge located in `src/renderer/bridge/`. Once connected, the server instantiates an `RpcRouter` from [`src/shared/rpc.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/shared/rpc.ts) to handle the shared RPC protocol used by both desktop and server editions. This router multiplexes all IPC calls—including file-system operations, Git services, and agent-status updates—over the WebSocket connection, allowing the same core services to function in a pure browser environment.

```typescript
// src/server/ws.ts
import { WebSocketServer } from 'ws';
import { RpcRouter } from '../shared/rpc';
import { ServerPlatform } from './platform-server';

export function createWsServer(http, platform: ServerPlatform) {
  const wss = new WebSocketServer({ server: http });

  wss.on('connection', (socket) => {
    const router = new RpcRouter(socket, platform);
    router.registerHandlers();   // registers all core RPC methods
  });
}

```

## ServerPlatform Shim Implementation

The critical abstraction enabling browser compatibility resides in [`src/server/platform-server.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/platform-server.ts). This file provides the `ServerPlatform` class, which implements the same `CorePlatform` interface used by the desktop application but isolates the renderer from any Electron API imports.

`ServerPlatform` fulfills the core contract by forwarding RPC calls to appropriate server-side handlers. For example, when the renderer invokes file-system operations, the shim translates these calls into method invocations that execute in the Node.js environment rather than the browser sandbox. This architectural boundary ensures the React components remain platform-agnostic, running identically whether loaded in Electron or served to a browser.

```typescript
// src/server/main.ts
import { createHttpServer } from './http';
import { createWsServer } from './ws';
import { ServerPlatform } from './platform-server';

// Initialise the core platform (shared with the desktop)
const platform = new ServerPlatform();

// Create the HTTP server that serves the renderer bundle
const http = createHttpServer({ staticRoot: 'out/renderer' });

// Attach the WebSocket RPC server to the same listener
createWsServer(http, platform);

// Listen on the configured port (default 3000)
http.listen(3000, () => console.log('nodeterm server running on http://localhost:3000'));

```

## Request Routing and Core Services

The `src/server/handlers/` directory contains modular HTTP handlers for specific domain features such as file-system access, Git integration, download endpoints, and GitHub control. The main router in [`src/server/handlers/index.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/handlers/index.ts) registers these handlers with the HTTP server, exposing them through the RPC layer to browser clients.

When the browser invokes operations like `fs:list` or `git:status`, these calls traverse the WebSocket connection to the `ServerPlatform` shim, which routes them to the appropriate handler in the core services layer. This architecture reuses the identical `src/core/**` modules employed by the desktop application, ensuring behavioral consistency across both editions.

```typescript
// In the renderer (browser) side
window.nodeTerminal.fs.list('/home/user/project')
  .then((entries) => console.log('Project files:', entries));

```

## Real-Time Agent Status Broadcasting

Live synchronization features such as unread badges and Kanban board updates rely on [`src/server/agent-status.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/agent-status.ts). This module subscribes to the core's agent status events and mirrors them to connected browsers via the WebSocket infrastructure.

When the server-side platform emits an `agent:status` update, the `broadcast` function from [`src/server/ws.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/ws.ts) forwards the payload to all connected clients. This mechanism maintains real-time state synchronization across multiple browser sessions, replicating the live experience of the desktop edition without requiring Electron's main process.

```typescript
// src/server/agent-status.ts
import { platform } from './platform-server';
import { broadcast } from './ws';

platform.on('agent:status', (status) => {
  broadcast('agent:status', status);   // forwards to all connected browsers
});

```

## Summary

- **Static asset serving**: [`src/server/http.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/http.ts) delivers the Vite-compiled renderer bundle (`out/renderer/`) to browsers as static files, initiating the React application.
- **WebSocket RPC**: The `/ws` endpoint in [`src/server/ws.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/ws.ts) implements the shared RPC protocol from [`src/shared/rpc.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/shared/rpc.ts), replacing Electron's IPC with web-native sockets.
- **Platform abstraction**: `ServerPlatform` in [`src/server/platform-server.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/platform-server.ts) implements the `CorePlatform` interface, isolating core logic from Electron APIs and enabling pure Node.js execution.
- **Service reuse**: The Server Edition leverages the same `src/core/**` services as the desktop app, routing requests through [`src/server/handlers/index.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/handlers/index.ts) to maintain feature parity.
- **Real-time sync**: Agent status updates propagate to browsers via [`src/server/agent-status.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/agent-status.ts), ensuring live UI elements remain synchronized across all connected clients.

## Frequently Asked Questions

### How does the Server Edition differ from the desktop Electron version?

The Server Edition replaces Electron's process boundaries with an HTTP and WebSocket stack. While the desktop version bundles the renderer in a native window using `ipcMain/ipcRenderer` for communication, the Server Edition serves the same React UI through a browser and multiplexes IPC calls over WebSocket connections via [`src/server/ws.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/ws.ts).

### What protocol does the browser use to communicate with the nodeterm server?

The browser communicates through a combination of standard HTTP for static assets and WebSocket for real-time RPC. Static files are served from [`src/server/http.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/http.ts), while the WebSocket endpoint at `/ws` (defined in [`src/server/ws.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/ws.ts)) handles all core service invocations using the protocol defined in [`src/shared/rpc.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/shared/rpc.ts).

### Can the Server Edition run without any Electron dependencies?

Yes. The `ServerPlatform` class in [`src/server/platform-server.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/platform-server.ts) implements the `CorePlatform` interface without importing Electron APIs. This allows the server to run in a pure Node.js environment, serving browsers while the core services remain identical to those used in the desktop application.

### How are real-time updates synchronized across browser clients?

The server subscribes to core agent status events through [`src/server/agent-status.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/agent-status.ts) and forwards them to all connected browsers using the `broadcast` function from [`src/server/ws.ts`](https://github.com/eneskirca/nodeterm/blob/main/src/server/ws.ts). This ensures that live badges, unread dots, and Kanban board states remain synchronized across all active browser sessions without polling.