# 通知設計書 2-WebSocket切断通知

## 概要

本ドキュメントは、Bun の Hot Module Reloading (HMR) 機能において、WebSocket 接続が切断された際にブラウザのコンソールに表示される警告メッセージ通知と、自動再接続処理の設計を記載する。

### 本通知の処理概要

この通知は、開発サーバーとブラウザクライアント間の WebSocket 接続が何らかの理由で切断されたことを開発者に警告し、自動的に再接続を試行することを知らせる。ネットワーク障害やサーバー再起動時に、開発者が接続状態を把握できるようにする。

**業務上の目的・背景**：開発中に WebSocket 接続が切断されると HMR 機能が動作しなくなり、コード変更がブラウザに反映されなくなる。この通知により、開発者は接続断の発生を即座に認識でき、自動再接続が行われることを把握できる。これにより、手動でのページリロードが不要であることを示し、開発体験の低下を防ぐ。

**通知の送信タイミング**：WebSocket の `onclose` イベントが発火した際に送信される。これは、サーバーが接続を閉じた場合、ネットワーク障害が発生した場合、またはサーバーが再起動された場合などに発生する。

**通知の受信者**：ブラウザのコンソールを通じて開発者に通知される。`console.warn()` メソッドで警告レベルとして出力されるため、通常のログよりも目立つ形で表示される。

**通知内容の概要**：`[Bun] Hot-module-reloading socket disconnected, reconnecting...` という固定メッセージがコンソールに出力される。このメッセージは、接続が切断され、システムが自動的に再接続を試行していることを示す。

**期待されるアクション**：開発者はこのメッセージを確認した後、再接続通知（`[Bun] Reconnected`）を待つ。再接続が成功しない場合は、サーバーの状態やネットワーク接続を確認する必要がある。通常は自動的に再接続されるため、特別なアクションは不要。

## 通知種別

コンソール通知（ブラウザ開発者ツール）- 警告レベル

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（onclose イベントハンドラ内で実行後、再接続処理を開始） |
| 優先度 | 中（警告通知のため） |
| リトライ | 無（コンソール出力は失敗しない。再接続処理は別途リトライあり） |

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

ブラウザの `console.warn()` メソッドを使用してコンソールに直接出力するため、特別な送信先決定ロジックは存在しない。

## 通知テンプレート

### コンソール出力

| 項目 | 内容 |
|-----|------|
| 出力レベル | warn |
| プレフィックス | `[Bun]` |

### 本文テンプレート

```
[Bun] Hot-module-reloading socket disconnected, reconnecting...
```

### 添付ファイル

該当なし（コンソール出力のため）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| なし | 固定メッセージのため変数なし | - | - |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| WebSocket イベント | `onclose` | 常に | WebSocket 接続が閉じられたとき |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| `closed` フラグが true | `wsProxy.close()` が明示的に呼び出された場合、再接続処理は行われない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[WebSocket 接続中] --> B{接続切断検出}
    B --> C[onclose イベント発火]
    C --> D[onStatusChange false 呼び出し]
    D --> E[console.warn でメッセージ出力]
    E --> F[1秒待機]
    F --> G[送信キュークリア]
    G --> H{closed フラグ確認}
    H -->|true| I[再接続中止]
    H -->|false| J[再接続ループ開始]
    J --> K[新規 WebSocket 作成]
    K --> L{接続成功?}
    L -->|成功| M[Reconnected 通知]
    L -->|失敗| N[待機後リトライ]
    N --> J
    M --> O[終了]
    I --> O
```

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

### 参照テーブル一覧

該当なし（クライアントサイドのコンソール出力のため、データベースアクセスは発生しない）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 再接続失敗 | サーバーが停止している、ネットワーク不通 | 再接続ループで継続的にリトライ |
| 明示的クローズ | `wsProxy.close()` が呼び出された | 再接続処理を中止（`closed` フラグで制御） |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 無制限（接続成功まで継続） |
| リトライ間隔 | `wait()` 関数による可変待機（フォーカス時は最大2.5秒、それ以外は即座） |
| リトライ対象エラー | すべての接続失敗 |

## 配信設定

### レート制限

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

### 配信時間帯

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

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

- この通知は開発環境でのみ使用されることを想定している
- 機密情報は含まれない（固定メッセージのみ）
- 再接続処理では同一の `/_bun/hmr` エンドポイントに対してのみ接続を試行する

## 備考

- 切断後、1秒の待機時間を設けてから再接続を開始する
- 再接続が成功した場合は「WebSocket再接続通知」（`[Bun] Reconnected`）が表示される
- `wait()` 関数は、ウィンドウがフォーカスされているかどうかで待機時間を調整する
- 送信キューは切断時にクリアされる

---

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

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

### 推奨読解順序

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

WebSocket 切断と再接続に関連する状態管理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | websocket.ts | `src/bake/client/websocket.ts` | `closed` フラグ（80行目）と `sendQueue`（83行目）の役割を理解する |
| 1-2 | websocket.ts | `src/bake/client/websocket.ts` | `wait` 関数（3-37行目）で再接続待機ロジックを理解する |

**読解のコツ**: `wait` 関数は、ウィンドウのフォーカス状態に応じて待機時間を調整する複雑なロジックを持つ。`document.hasFocus()` と `window.addEventListener('focus', ...)` の使い方に注目する。

#### Step 2: エントリーポイントを理解する

WebSocket 切断時のイベントハンドラを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | websocket.ts | `src/bake/client/websocket.ts` | `onClose` 関数（153-188行目）が切断時の処理を実行する |
| 2-2 | websocket.ts | `src/bake/client/websocket.ts` | 194行目で `ws.onclose = onClose` として設定される |

**主要処理フロー**:
1. **154行目**: `onStatusChange?.(false)` でコールバック呼び出し
2. **155行目**: `console.warn("[Bun] Hot-module-reloading socket disconnected, reconnecting...");` でメッセージ出力
3. **157行目**: 1秒待機
4. **160行目**: 送信キュークリア
5. **162-188行目**: 再接続ループ

#### Step 3: 再接続処理の詳細を理解する

再接続ループの内部処理を詳細に理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | websocket.ts | `src/bake/client/websocket.ts` | 162-188行目の `while (true)` ループで再接続を継続的に試行 |
| 3-2 | websocket.ts | `src/bake/client/websocket.ts` | 169-181行目で新しい WebSocket を作成し、接続結果を Promise で待機 |

**主要処理フロー**:
- **163行目**: `closed` フラグ確認（明示的クローズ時は中止）
- **169行目**: 新しい WebSocket インスタンス作成
- **171-176行目**: `onopen` ハンドラで接続成功時の処理
- **178-181行目**: `onerror` ハンドラで接続失敗時の処理
- **186行目**: 失敗時は `wait()` で待機後にリトライ

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

```
WebSocket.onclose
    │
    └─ onClose()
           │
           ├─ onStatusChange(false)
           │      └─ emitEvent('bun:ws:disconnect')
           │
           ├─ console.warn() ← 通知出力
           │
           ├─ setTimeout(1000)
           │
           ├─ sendQueue.length = 0 (キュークリア)
           │
           └─ while (true) 再接続ループ
                  │
                  ├─ if (closed) return
                  │
                  ├─ new WebSocket(url)
                  │
                  ├─ await promise (接続待機)
                  │
                  └─ if (!success) await wait()
```

### データフロー図

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

接続切断イベント ───────▶ onClose() ──────────────────▶ 警告メッセージ出力
                              │
                              ▼
                       onStatusChange(false)
                              │
                              ▼
                       console.warn() ────────────────▶ [Bun] Hot-module-reloading...
                              │
                              ▼
                       setTimeout(1000)
                              │
                              ▼
                       再接続ループ開始
                              │
                              ▼
                       new WebSocket() ───────────────▶ 接続試行
                              │
                    ┌─────────┴─────────┐
                    ▼                   ▼
              [成功]                 [失敗]
                 │                      │
                 ▼                      ▼
          console.info() ──▶   wait() + リトライ
          "Reconnected"
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| websocket.ts | `src/bake/client/websocket.ts` | ソース | WebSocket 接続管理、切断検出、再接続処理 |
| hmr-runtime-client.ts | `src/bake/hmr-runtime-client.ts` | ソース | HMR クライアントのエントリーポイント、イベントハンドラ登録 |
| hmr-module.ts | `src/bake/hmr-module.ts` | ソース | HMR イベント発行（`emitEvent` 関数で `bun:ws:disconnect` を発行） |
