
# アーキテクチャ

## 全体の流れ

デフォルト（ローカルtmux + トンネル）:

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

直接サンドボックスモード（Daytona、トンネルなし）:

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

`--no-tunnel`が設定されている場合、TermbridgeはCloudflareを経由せず、指定されたパブリックURLを使用します。

## コンポーネント

### CLIプロセス

- UIアセットを配信するHTTPサーバーを起動します。
- ターミナルI/O用のWebSocketサーバーを起動します。
- 1つ以上のtmuxセッション（またはDaytona PTY）を作成します。
- 1回限りの引き換えトークンを発行します。
- 有効な場合はトンネル（現在はCloudflare）を起動して監視します。
- 直接サンドボックスモードでは、サンドボックス内でTermbridgeを起動し、共有URLを待ちます。

### ターミナルバックエンド

- **tmuxバックエンド**: `node-pty`を使ってtmuxに接続し、実際のキー入力と出力を扱います。
- **Daytonaバックエンド**: サンドボックス内のDaytona PTYを使用します。
- フルカラー対応のため`TERM=xterm-256color`と`COLORTERM=truecolor`を設定します。
- tmuxでは、UIをすっきり保つため、tmuxのステータスバーを無効にします。

### ターミナルレジストリ

- 利用可能なターミナルセッションを管理します。
- UIに一覧を提供し、選択されたターミナルIDを検証します。

### 認証とセッション

- 1回限りのトークンはURLとして出力され、QRコードに埋め込まれます。
- `GET /__tb/s/:token`がトークンを引き換え、Cookieセッションを設定します。
- WebSocket接続には、有効なセッションCookieとCSRFトークンが必要です。
- CSRFトークンは`GET /__tb/api/csrf`で取得し、WebSocketのクエリパラメーターで渡します。

### プロキシモード

`--proxy <port>`を渡した場合:
- すべてのtermbridgeルートは`/__tb/`プレフィックスの下に配置されます
- `/__tb/`リクエストはターゲットアプリにプロキシされます
- UIにより、Views切り替え機能からTerminal/Previewビューを表示できます
- Previewビューは`/`を指すiframeを読み込みます
- HMR用のWebSocket接続はターゲットに転送されます

### セキュリティ

- **CSRF対策**: クロスサイトハイジャックを防ぐため、WebSocketへのアップグレードにはCSRFトークンが必要です。
- **入力制限**: 64KBのHTTP本文、1MBのWebSocketメッセージ、メッセージごとに64KBのターミナル入力。
- **レート制限**: トークン引き換えとWebSocket接続に対し、IP単位で制限します。

## APIエンドポイント

プロキシ対象アプリとの競合を避けるため、すべてのルートは`/__tb/`プレフィックスの下に配置されます:

- `GET /__tb/healthz` - ヘルスチェック
- `GET /__tb/s/:token` - トークン引き換え → Cookie設定 → リダイレクト
- `GET /__tb/api/terminals` - ターミナル一覧の取得
- `GET /__tb/api/csrf` - WebSocket用CSRFトークンの取得
- `GET /__tb/api/config` - 設定の取得（proxyPort、devProxyUrl）
- `POST /__tb/api/terminals` - 新しいtmuxセッションの作成
- `GET /__tb/app/*` - SPAフォールバック
- `WS /__tb/ws/terminal/:terminalId?csrf=<token>` - ターミナルI/Oのストリーミング

プロキシモードが有効な場合:
- `GET /` - プロキシ対象アプリにリダイレクト（無効の場合は`/__tb/app`）
- `* /*` - ターゲットアプリにプロキシ

## WebSocketプロトコル

クライアント → サーバー:

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

サーバー → クライアント:

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

## UIスタック

- Vite + TanStack Router
- xterm.js + Fitアドオン + WebGLレンダラー
- 固定入力バーを備えたモバイル優先のレイアウト
- 最大10回の再試行を行う指数バックオフ付き自動再接続
- 接続状態インジケーター
