# 通知設計書 7-ランタイムエラー通知

## 概要

本ドキュメントは、Bun の Hot Module Reloading (HMR) 機能において、JavaScript の実行時エラー（ランタイムエラー）が発生した際にブラウザ上のオーバーレイ UI で表示される通知の設計を記載する。

### 本通知の処理概要

この通知は、ブラウザ上で JavaScript コードの実行中に発生したエラー（TypeError、ReferenceError、未処理の Promise rejection など）を、開発者が即座に認識できるようにオーバーレイとして表示する。エラー名、メッセージ、スタックトレース、およびソースマップを使用してリマップされた正確なエラー発生位置を視覚的に提示する。

**業務上の目的・背景**：開発中にランタイムエラーが発生した場合、コンソールだけでは見落とされる可能性がある。特にバンドルされたコードでは、スタックトレースが読みにくくなることがある。オーバーレイ UI によりエラーを画面全体に表示し、ソースマップを使用して元のソースコードの位置を表示することで、開発者が迅速にデバッグできるようにする。

**通知の送信タイミング**：`window.addEventListener('error')` または `window.addEventListener('unhandledrejection')` によってキャプチャされたエラーが発生した際に、クライアントサイドで処理され、オーバーレイに表示される。また、サーバーに `/_bun/report_error` エンドポイントを通じてエラーが報告され、スタックトレースのリマッピングが行われる。

**通知の受信者**：ブラウザ上のオーバーレイ UI を通じて開発者に通知される。オーバーレイは画面全体を覆うモーダルダイアログとして表示される。

**通知内容の概要**：エラー名（error, TypeError など）、エラーメッセージ、リマップされたスタックトレース、およびエラー発生位置のコードプレビューが表示される。複数のランタイムエラーがある場合は、ナビゲーションバーで切り替え可能。

**期待されるアクション**：開発者はオーバーレイに表示されたエラー情報を確認し、該当するコードを修正する。ランタイムエラーはビルドエラーと異なり、「Dismiss All」ボタンで一時的に非表示にできる（ただしビルドエラーが存在しない場合のみ）。

## 通知種別

オーバーレイ UI（ブラウザ内モーダル）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（エラーイベントキャプチャ後、サーバーへの POST リクエストでリマッピング） |
| 優先度 | 高（ランタイムエラーはアプリケーション動作に影響） |
| リトライ | 無（リマッピング失敗時は元のスタックトレースを表示） |

### 送信先決定ロジック

エラーが発生したブラウザタブのオーバーレイに直接表示される。サーバーへのエラー報告は `/_bun/report_error` エンドポイントに POST リクエストで送信される。

## 通知テンプレート

### オーバーレイ表示

| 項目 | 内容 |
|-----|------|
| モーダルタイトル | `Runtime Error` / `Unhandled Promise Rejection` |
| 背景色 | 半透明ダーク（`#8883`） |
| Z-index | `2147483647`（最前面） |

### エラー表示構造

```
[エラー名]: [エラーメッセージ]

 123 | [コード行]
     |     ^^^^^ (エラー位置をハイライト)

at [関数名] in [ファイル名]:行:列
at [関数名] in [ファイル名]:行:列
...
```

### 添付ファイル

該当なし（オーバーレイ UI での表示）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| `name` | エラー名（Error, TypeError など） | `error.name` | Yes |
| `message` | エラーメッセージ | `error.message` | Yes |
| `trace` | リマップされたスタックトレース | サーバーレスポンス | No |
| `code` | エラー発生位置のコードプレビュー | サーバーレスポンス | No |
| `async` | 未処理 Promise rejection かどうか | イベントタイプ | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| グローバルエラー | `window.error` | 常に | キャッチされていない JavaScript エラー |
| Promise rejection | `window.unhandledrejection` | 常に | 未処理の Promise rejection |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| なし | すべてのランタイムエラーが表示対象 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[JavaScript エラー発生] --> B{エラータイプ}
    B -->|window.error| C[error イベントキャプチャ]
    B -->|Promise rejection| D[unhandledrejection イベントキャプチャ]
    C --> E[onRuntimeError 呼び出し]
    D --> E
    E --> F[hasFatalError = true 設定]
    F --> G[スタックトレース解析]
    G --> H[バイナリデータ生成]
    H --> I[/_bun/report_error POST]
    I --> J{レスポンス成功?}
    J -->|Yes| K[リマップされたトレース取得]
    J -->|No| L[元のトレース使用]
    K --> M[runtimeErrors 配列に追加]
    L --> M
    M --> N[updateErrorOverlay 呼び出し]
    N --> O[オーバーレイ表示]
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（メモリ上のデータ構造を使用）

### クライアントサイドデータ構造

| 変数名 | 型 | 用途 |
|--------|------|------|
| `runtimeErrors` | `RuntimeError[]` | ランタイムエラーのリスト |
| `activeErrorIndex` | `number` | 現在表示中のエラーインデックス（-1 はビルドエラー表示） |

### RuntimeError 構造

```typescript
interface RuntimeError {
  name: string;        // エラー名
  message: string;     // エラーメッセージ
  trace: RemappedFrame[]; // リマップされたスタックトレース
  remapped: boolean;   // リマッピング成功したか
  async: boolean;      // Promise rejection かどうか
  code?: CodePreview;  // コードプレビュー（オプション）
}
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| リマッピング失敗 | サーバーが応答しない、エラーレスポンス | 元のスタックトレースを使用して表示 |
| スタックトレース解析失敗 | 不正な error.stack 形式 | 空のトレースで表示 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 該当なし（失敗時は元のトレースを使用） |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（開発時に随時発生）

## セキュリティ考慮事項

- この通知は開発環境でのみ使用されることを想定している
- エラーメッセージにはソースコードの一部が含まれる可能性がある
- スタックトレースにはファイルパス情報が含まれる
- `/_bun/report_error` エンドポイントは開発サーバーでのみ利用可能であるべき
- 本番環境では HMR 機能自体が無効化されるべきである

## 備考

- ランタイムエラーは `hasFatalError` フラグを true に設定する（致命的エラーとして扱う）
- ランタイムエラーとビルドエラーは同時に存在可能で、ナビゲーションバーで切り替える
- ビルドエラーが存在しない場合のみ、「Dismiss All」ボタンでランタイムエラーを非表示にできる
- エラー発生行のコードプレビューはサーバーサイドで生成され、シンタックスハイライトが適用される

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

ランタイムエラーの表現に使用されるデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | overlay.ts | `src/bake/client/overlay.ts` | 103-116行目の `RuntimeError` インターフェースを理解する |
| 1-2 | overlay.ts | `src/bake/client/overlay.ts` | 118-125行目の `CodePreview` インターフェースを理解する |
| 1-3 | stack-trace.ts | `src/bake/client/stack-trace.ts` | `Frame` インターフェースでスタックフレームの構造を理解する |

**読解のコツ**: `RuntimeError.trace` はリマップ前後で異なる `Frame` 配列を保持する。`remapped` フラグでリマッピングの成否を判定できる。

#### Step 2: エラーキャプチャを理解する

グローバルエラーイベントのキャプチャ方法を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | hmr-runtime-client.ts | `src/bake/hmr-runtime-client.ts` | 239-250行目の `window.addEventListener('error')` でエラーキャプチャ |
| 2-2 | hmr-runtime-client.ts | `src/bake/hmr-runtime-client.ts` | 252-254行目の `window.addEventListener('unhandledrejection')` で Promise rejection キャプチャ |

**主要処理フロー**:
1. **239-250行目**: `error` イベントリスナー登録
2. **242-243行目**: `event.error` または `event.message` からエラー値を取得
3. **249行目**: `onRuntimeError(value, true, false)` 呼び出し

#### Step 3: エラー処理と報告を理解する

`onRuntimeError` 関数の処理フローを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | overlay.ts | `src/bake/client/overlay.ts` | 216-334行目の `onRuntimeError` 関数でエラー処理全体を理解 |
| 3-2 | overlay.ts | `src/bake/client/overlay.ts` | 244-263行目でバイナリデータ生成 |
| 3-3 | overlay.ts | `src/bake/client/overlay.ts` | 266-269行目で `/_bun/report_error` POST |

**主要処理フロー**:
- **218-219行目**: `hasFatalError = true` 設定
- **223-238行目**: エラー名とメッセージの正規化
- **239行目**: `parseStackTrace(err)` でスタックトレース解析
- **244-263行目**: `DataViewWriter` でバイナリデータ生成
- **266-269行目**: `fetch('/_bun/report_error')` でサーバー報告
- **274-317行目**: レスポンス解析とリマップされたトレース取得

#### Step 4: オーバーレイ表示を理解する

ランタイムエラーのオーバーレイ表示処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | overlay.ts | `src/bake/client/overlay.ts` | 463-524行目の `updateRuntimeErrorOverlay` 関数で表示処理を理解 |

**主要処理フロー**:
- **416行目**: モーダルタイトル設定（`Runtime Error` / `Unhandled Promise Rejection`）
- **468-474行目**: エラー名とメッセージの表示
- **475-514行目**: コードプレビューとハイライト表示
- **516-522行目**: スタックトレース表示

### プログラム呼び出し階層図

```
window.addEventListener('error')
    │
    └─ onRuntimeError(value, fatal=true, async=false)
           │
           ├─ hasFatalError = true
           │
           ├─ parseStackTrace(err)
           │      └─ スタックトレース解析
           │
           ├─ DataViewWriter でバイナリデータ生成
           │
           ├─ fetch('/_bun/report_error', { method: 'POST' })
           │      │
           │      └─ サーバーでリマッピング処理
           │
           ├─ レスポンス解析
           │      │
           │      ├─ [成功] リマップされたトレース取得
           │      │
           │      └─ [失敗] 元のトレース使用
           │
           ├─ runtimeErrors.push()
           │
           └─ updateErrorOverlay()
                  │
                  ├─ mountModal()
                  │
                  ├─ updateRuntimeErrorOverlay()
                  │      │
                  │      ├─ エラー名/メッセージ表示
                  │      │
                  │      ├─ コードプレビュー表示
                  │      │
                  │      └─ スタックトレース表示
                  │
                  └─ setModalVisible(true)
```

### データフロー図

```
[入力]                    [処理]                         [出力]

JavaScript
エラー発生 ─────────▶ window.error イベント
                              │
                              ▼
                    onRuntimeError()
                              │
                    ┌─────────┴─────────┐
                    ▼                   ▼
            parseStackTrace()   hasFatalError = true
                    │
                    ▼
            DataViewWriter.write()
                    │
                    ▼
            fetch('/_bun/report_error')
                    │
                    ▼
            サーバーレスポンス解析 ──────────────▶ runtimeErrors 配列追加
                    │
                    ▼
            updateErrorOverlay()
                    │
                    ▼
            updateRuntimeErrorOverlay() ─────────▶ オーバーレイ表示
                    │
                    ▼
            [エラー情報表示]
             - エラー名/メッセージ
             - コードプレビュー
             - スタックトレース
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| overlay.ts | `src/bake/client/overlay.ts` | ソース | オーバーレイ UI の実装、`onRuntimeError` 関数 |
| hmr-runtime-client.ts | `src/bake/hmr-runtime-client.ts` | ソース | グローバルエラーイベントリスナー登録 |
| stack-trace.ts | `src/bake/client/stack-trace.ts` | ソース | スタックトレース解析、`parseStackTrace` 関数 |
| data-view.ts | `src/bake/client/data-view.ts` | ソース | バイナリデータ読み書き |
| JavaScriptSyntaxHighlighter.ts | `src/bake/client/JavaScriptSyntaxHighlighter.ts` | ソース | コードプレビューのシンタックスハイライト |
