# 通知設計書 22-Turbopack接続通知

## 概要

本ドキュメントは、Next.js開発サーバーにおけるTurbopack接続通知の設計を記述する。TurbopackモードでWebSocket接続が確立された際にブラウザクライアントへセッションIDを送信し、HMRセッションの同一性を管理する仕組みについて定義する。

### 本通知の処理概要

Turbopackモードの開発サーバーでブラウザクライアントがWebSocket接続を確立した際、サーバーからクライアントへ`turbopack-connected`メッセージをセッションIDとともに送信する。クライアントはこのセッションIDを用いてHMR更新の整合性を管理する。

**業務上の目的・背景**：Turbopackモードでは、開発サーバーの再起動やホットリロード時にセッションが変わる可能性がある。セッションIDをクライアントに通知することで、古いセッションのHMR更新を検出し、必要に応じてフルリロードを実行できるようにする。これにより開発中の状態不整合を防止する。

**通知の送信タイミング**：WebSocketの`handleUpgrade`コールバック内で、クライアント接続完了直後に送信される。各クライアントの接続時に1回ずつ送信される。

**通知の受信者**：新たにWebSocket接続を確立した個別のブラウザクライアント。ブロードキャストではなく、接続したクライアント1つに対して送信される。

**通知内容の概要**：`type: "turbopack-connected"`と`data: { sessionId: number }`を含むJSONメッセージ。`sessionId`はサーバー起動時にランダム生成される整数値。

**期待されるアクション**：App Routerクライアント（`hot-reloader-app.tsx`）は`processTurbopackMessage`関数を通じてTurbopack HMRハンドラーにセッション情報を伝達する。Pages Routerクライアント（`page-bootstrap.ts`）ではno-opとして処理される。

## 通知種別

WebSocket（HMR）メッセージ（アプリ内通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（WebSocket接続確立時に即座に送信） |
| 優先度 | 高（接続確立直後の最初のメッセージ） |
| リトライ | なし（接続確立時の1回送信） |

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

`onHMR`ハンドラー内の`wsServer.handleUpgrade`コールバックで、接続が確立されたクライアントに対して`sendToClient(client, turbopackConnectedMessage)`を呼び出す。ブロードキャストではなく個別送信。

## 通知テンプレート

### メール通知の場合

該当なし（WebSocketメッセージのため）

### 本文テンプレート

```json
{
  "type": "turbopack-connected",
  "data": {
    "sessionId": 1234567890123456
  }
}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| type | メッセージ種別 | 固定値 `"turbopack-connected"` | Yes |
| data.sessionId | サーバーセッション識別子 | `Math.floor(Number.MAX_SAFE_INTEGER * Math.random())` で生成 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| サーバーイベント | WebSocket接続確立（handleUpgrade完了） | 常に送信 | クライアントがHMR WebSocketに接続した直後 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| なし | WebSocket接続確立時は必ず送信される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ブラウザからWebSocket接続要求] --> B[wsServer.handleUpgrade]
    B --> C[クライアント状態初期化]
    C --> D[turbopack-connectedメッセージ送信]
    D --> E[SYNCメッセージ送信]
    E --> F[クライアント: processTurbopackMessage呼び出し]
    F --> G[TurbopackHmrにセッション情報伝達]
```

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

### 参照テーブル一覧

該当なし（データベースは使用しない）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| WebSocketアップグレード失敗 | HTTP→WebSocketアップグレードが失敗 | wsServerが接続を拒否し、本メッセージは送信されない |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

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

### 配信時間帯

制限なし（開発サーバー稼働中は常時送信可能）

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

本通知はローカル開発環境専用であり、本番環境では送信されない。セッションIDはランダム整数であり、機密情報は含まれない。

## 備考

- `sessionId`はサーバープロセスの起動ごとに1回だけ生成される（`hot-reloader-turbopack.ts`の142行目）。サーバー再起動時に新しいIDが割り当てられるため、古いセッションのクライアントはセッションの不一致を検出できる。
- SYNCメッセージの送信前に`turbopack-connected`が送信されるため、クライアントはSYNC受信時点でセッションIDを把握している。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | hot-reloader-types.ts | `packages/next/src/server/dev/hot-reloader-types.ts` | 33行目: `TURBOPACK_CONNECTED = 'turbopack-connected'`のenum定義。137-140行目: `TurbopackConnectedMessage`インターフェースで`data: { sessionId: number }`の構造を確認 |

**読解のコツ**: `TurbopackMessageSentToBrowser`型（209-217行目）にも`TURBOPACK_CONNECTED`が含まれており、Turbopack固有のメッセージ型として分類されている。

#### Step 2: エントリーポイントを理解する（サーバー側送信）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | hot-reloader-turbopack.ts | `packages/next/src/server/dev/hot-reloader-turbopack.ts` | 142行目: `sessionId`のランダム生成。888-1122行目: `onHMR`メソッドの全体。1079-1083行目: `turbopackConnectedMessage`の生成と送信 |

**主要処理フロー**:
1. **142行目**: `const sessionId = Math.floor(Number.MAX_SAFE_INTEGER * Math.random())`でセッションID生成
2. **888行目**: `onHMR`メソッドでWebSocket接続処理開始
3. **889行目**: `wsServer.handleUpgrade`でHTTPからWebSocketへアップグレード
4. **933行目**: `clientStates.set`でクライアント状態を初期化
5. **1079-1083行目**: `TurbopackConnectedMessage`を生成し`sendToClient`で送信

#### Step 3: クライアント側受信処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | hot-reloader-app.tsx | `packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx` | 375-383行目: App RouterでTURBOPACK_CONNECTEDメッセージを受信し`processTurbopackMessage`を呼び出す |
| 3-2 | web-socket.ts | `packages/next/src/client/dev/hot-reloader/app/web-socket.ts` | Turbopack WebSocket接続のクライアント側ハンドリング |

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

```
onHMR(req, socket, head, onUpgrade) [hot-reloader-turbopack.ts:888]
    |
    +-- wsServer.handleUpgrade(req, socket, head, callback) [hot-reloader-turbopack.ts:889]
           |
           +-- clientStates.set(client, {...}) [hot-reloader-turbopack.ts:933]
           |
           +-- sendToClient(client, turbopackConnectedMessage) [hot-reloader-turbopack.ts:1083]
           |      |
           |      +-- client.send(JSON.stringify(message)) [hot-reloader-turbopack.ts:454-461]
           |
           +-- sendToClient(client, syncMessage) [hot-reloader-turbopack.ts:1120]
```

### データフロー図

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

ブラウザWebSocket    ──> wsServer.handleUpgrade()    ──> JSON メッセージ
  接続要求                 セッションID参照                type: "turbopack-connected"
                          (モジュール変数sessionId)       data: { sessionId: <number> }
                                                           |
                                                           v
                                                      [ブラウザクライアント]
                                                      processTurbopackMessage()
                                                      TurbopackHmrセッション管理
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| hot-reloader-types.ts | `packages/next/src/server/dev/hot-reloader-types.ts` | ソース | メッセージ型定義・enum定義 |
| hot-reloader-turbopack.ts | `packages/next/src/server/dev/hot-reloader-turbopack.ts` | ソース | サーバー側送信ロジック |
| hot-reloader-app.tsx | `packages/next/src/client/dev/hot-reloader/app/hot-reloader-app.tsx` | ソース | App Routerクライアント側受信処理 |
| web-socket.ts | `packages/next/src/client/dev/hot-reloader/app/web-socket.ts` | ソース | Turbopack WebSocketクライアント |
| page-bootstrap.ts | `packages/next/src/client/page-bootstrap.ts` | ソース | Pages Routerクライアント（no-op） |
