
# Architecture

## High-level flow

Default (local tmux + tunnel):

```
Browser (phone)
  |
  | HTTPS
  v
Cloudflare Quick Tunnel
  |
  | HTTP/WS
  v
Local Termbridge server
  |
  | PTY
  v
Tmux session
```

Direct sandbox mode (Daytona, no tunnel):

```
Browser (phone)
  |
  | HTTPS
  v
Daytona preview link
  |
  | HTTP/WS
  v
Termbridge server (sandbox)
  |
  | PTY
  v
Tmux session (sandbox)
```

When `--no-tunnel` is set, Termbridge skips Cloudflare and uses your provided public URL.

## Components

### CLI process

- Starts the HTTP server that serves the UI assets.
- Starts the WebSocket server for terminal I/O.
- Creates one or more tmux sessions (or Daytona PTYs).
- Issues one-time redemption tokens.
- Starts and monitors the tunnel when enabled (Cloudflare today).
- In direct sandbox mode, launches Termbridge inside the sandbox and waits for the share URL.

### Terminal backend

- **tmux backend**: Uses `node-pty` to attach to tmux for real keystrokes and output.
- **Daytona backend**: Uses Daytona PTYs inside a sandbox.
- Sets `TERM=xterm-256color` and `COLORTERM=truecolor` for full color support.
- For tmux, disables the tmux status bar to keep the UI clean.

### Terminal registry

- Tracks available terminal sessions.
- Provides a list for the UI and validates selected terminal IDs.

### Auth and session

- One-time token is printed as a URL and encoded in a QR code.
- `GET /__tb/s/:token` redeems the token and sets a cookie session.
- WebSocket connections require a valid session cookie and CSRF token.
- CSRF token fetched via `GET /__tb/api/csrf` and passed in WebSocket query param.

### Proxy mode

When `--proxy <port>` is passed:
- All termbridge routes live under `/__tb/` prefix
- Non-`/__tb/` requests are proxied to the target app
- UI exposes Terminal/Preview views via the Views switcher
- Preview view loads an iframe pointing to `/`
- WebSocket connections for HMR are forwarded to the target

### Security

- **CSRF protection**: WebSocket upgrades require a CSRF token to prevent cross-site hijacking.
- **Input limits**: 64KB HTTP body, 1MB WebSocket message, 64KB terminal input per message.
- **Rate limiting**: Per-IP limits on token redemption and WebSocket connections.

## API endpoints

All routes live under the `/__tb/` prefix to avoid conflicts with proxied apps:

- `GET /__tb/healthz` - health check
- `GET /__tb/s/:token` - token redemption → cookie → redirect
- `GET /__tb/api/terminals` - list terminals
- `GET /__tb/api/csrf` - get CSRF token for WebSocket
- `GET /__tb/api/config` - get config (proxyPort, devProxyUrl)
- `POST /__tb/api/terminals` - create a new tmux session
- `GET /__tb/app/*` - SPA fallback
- `WS /__tb/ws/terminal/:terminalId?csrf=<token>` - stream terminal I/O

When proxy mode is enabled:
- `GET /` - redirects to proxied app (or `/__tb/app` if disabled)
- `* /*` - proxied to target app

## WebSocket protocol

Client -> server:

```json
{ "type": "input", "data": "ls -la" }
{ "type": "resize", "cols": 120, "rows": 32 }
{ "type": "control", "key": "ctrl_c" }
```

Server -> client:

```json
{ "type": "output", "data": "..." }
{ "type": "status", "state": "connected" }
```

## UI stack

- Vite + TanStack Router
- xterm.js + Fit addon + WebGL renderer
- Mobile-first layout with a fixed input bar
- Auto-reconnect with exponential backoff (up to 10 retries)
- Connection status indicator
