# 機能設計書 77-Web Streams

## 概要

本ドキュメントは、BunのWeb Streams API機能の機能設計を記述する。Web Streamsは、WHATWG Streams Standardに準拠したストリーム処理APIを提供し、ReadableStream、WritableStream、TransformStreamの3つの主要なクラスで構成される。

### 本機能の処理概要

Web Streams APIは、データを小さなチャンクに分割して逐次処理するための標準化されたAPIを提供する。メモリ効率の良いデータ処理、バックプレッシャー制御、パイプライン処理などを実現する。

**業務上の目的・背景**：大規模なデータの効率的な処理、リアルタイムデータストリーミング、ファイルI/O、ネットワーク通信など、メモリ制約のある環境でのデータ処理に使用される。ブラウザAPIとの互換性により、フロントエンドとバックエンドでコードを共有可能。

**機能の利用シーン**：
- 大容量ファイルの読み書き
- HTTPレスポンスのストリーミング
- データ変換パイプライン
- 動画/音声ストリーミング
- リアルタイムログ処理
- 圧縮/解凍処理

**主要な処理内容**：
1. ReadableStreamでデータソースからの読み取り
2. WritableStreamでデータシンクへの書き込み
3. TransformStreamでデータ変換
4. pipeThrough/pipeToでストリーム連結
5. バックプレッシャーによる流量制御

**関連システム・外部連携**：Bun.file、fetch、Bun.serveなど多くのAPIがStreams APIを使用。ファイルシステム、ネットワーク層と連携。

**権限による制御**：特に権限による制御は行われない。すべてのコードから利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | コマンドライン/API経由での利用（画面なし） |

## 機能種別

データストリーミング / 非同期I/O

## 入力仕様

### ReadableStreamコンストラクタ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| underlyingSource | object | No | データソース定義 | - |
| queuingStrategy | object | No | キューイング戦略 | - |

### UnderlyingSourceオプション

| オプション | 型 | 説明 |
|-----------|-----|------|
| start | function | 初期化時に呼ばれる |
| pull | function | データが必要な時に呼ばれる |
| cancel | function | キャンセル時に呼ばれる |
| type | string | "bytes"でバイトストリーム |
| autoAllocateChunkSize | number | 自動割り当てサイズ |

### WritableStreamコンストラクタ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| underlyingSink | object | No | データシンク定義 | - |
| queuingStrategy | object | No | キューイング戦略 | - |

### 入力データソース

API呼び出し時の引数として直接指定。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ReadableStream | object | 読み取り可能ストリーム |
| WritableStream | object | 書き込み可能ストリーム |
| TransformStream | object | 変換ストリーム |

### ReadableStreamメソッド

| メソッド | 説明 |
|---------|------|
| getReader() | リーダーを取得 |
| pipeThrough(transform) | 変換ストリームを通す |
| pipeTo(writable) | 書き込みストリームに接続 |
| tee() | ストリームを分岐 |
| cancel() | ストリームをキャンセル |

### WritableStreamメソッド

| メソッド | 説明 |
|---------|------|
| getWriter() | ライターを取得 |
| close() | ストリームを閉じる |
| abort() | ストリームを中断 |

### 出力先

ストリームオブジェクトとして返却。

## 処理フロー

### 処理シーケンス（ReadableStream）

```
1. ReadableStream作成
   └─ underlyingSourceとstrategyを設定
2. start()呼び出し
   └─ ソースの初期化
3. データ読み取りループ
   └─ pull()でデータをキューに追加
   └─ バックプレッシャー制御
4. 終了処理
   └─ close()またはcancel()
```

### フローチャート

```mermaid
flowchart TD
    A[ReadableStream作成] --> B[start callback]
    B --> C{データ要求?}
    C -->|Yes| D[pull callback]
    D --> E[controller.enqueue]
    E --> F{バッファ満杯?}
    F -->|Yes| G[バックプレッシャー]
    F -->|No| C
    G --> H[消費待ち]
    H --> C
    C -->|完了| I[close]
    C -->|エラー| J[error/cancel]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-77-01 | ロック | getReader/getWriter呼び出し時にストリームをロック | 常時 |
| BR-77-02 | disturbed | 一度読み始めたストリームはdisturbed状態 | 常時 |
| BR-77-03 | tee制約 | teeはストリーム全体をメモリにバッファリングする可能性 | tee使用時 |
| BR-77-04 | バックプレッシャー | highWaterMarkを超えるとpullが呼ばれない | 常時 |

### 計算ロジック

なし

## データベース操作仕様

### 操作別データベース影響一覧

なし（データベース操作を行わない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| TypeError | Error | ロック中のストリームにアクセス | releaseLockを呼び出す |
| TypeError | Error | 閉じたストリームに書き込み | 新しいストリームを作成 |
| AbortError | Error | ストリームが中断された | 正常な中断処理 |

### リトライ仕様

なし（呼び出し側で制御）

## トランザクション仕様

なし

## パフォーマンス要件

- チャンク単位の処理でメモリ効率を向上
- バックプレッシャーで過負荷を防止
- パイプラインで効率的なデータ転送

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

- ストリームはロック機構で不正アクセスを防止
- データはチャンク単位で処理されメモリ露出を最小化

## 備考

Bunで内部的に使用されるストリームソース：
- Blob（ByteBlobLoader）
- File（FileReader）
- HTTP Response（HTTPResponseSink）
- Network（NetworkSink）
- ArrayBuffer（ArrayBufferSink）

---

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

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

### 推奨読解順序

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

ストリーム関連の型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | streams.zig | `src/bun.js/webcore/streams.zig` | Start union型（1-66行目） |
| 1-2 | ReadableStream.zig | `src/bun.js/webcore/ReadableStream.zig` | ReadableStream構造体（1-100行目） |

**読解のコツ**: Start unionでストリーム開始時のオプションを表現。各シンクタイプ（ArrayBufferSink、FileSink等）が異なる設定を持つ。

**主要処理フロー**:
1. **1-30行目**: Start union型のタグ定義
2. **32-53行目**: toJSでJSValueに変換
3. **55-66行目**: fromJSでJSからパース

#### Step 2: ReadableStreamを理解する

読み取り可能ストリームの実装。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ReadableStream.zig | `src/bun.js/webcore/ReadableStream.zig` | Strong構造体（6-49行目） |
| 2-2 | ReadableStream.zig | `src/bun.js/webcore/ReadableStream.zig` | tee関数（52-61行目） |

**主要処理フロー**:
- **6-49行目**: Strong構造体で強参照を管理
- **52-61行目**: tee()でストリームを分岐（extern関数呼び出し）
- **75-100行目**: toAnyBlobでBlobへ変換

#### Step 3: シンク実装を理解する

各種シンクの実装パターン。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | streams.zig | `src/bun.js/webcore/streams.zig` | fromJSWithTag（68-150行目） |
| 3-2 | Sink.zig | `src/bun.js/webcore/Sink.zig` | シンク共通インターフェース |

**主要処理フロー**:
- **78-114行目**: ArrayBufferSinkのオプション解析
- **115-150行目**: FileSinkのオプション解析（path/fd）

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

```
new ReadableStream(source, strategy)
    │
    ├─ source.start(controller)
    │      └─ 初期化処理
    │
    ├─ source.pull(controller)
    │      ├─ controller.enqueue(chunk)
    │      └─ controller.close()
    │
    └─ pipeThrough / pipeTo
           ├─ TransformStream
           │      ├─ transform(chunk, controller)
           │      └─ flush(controller)
           │
           └─ WritableStream
                  └─ sink.write(chunk)

内部ストリームソース:
ReadableStream.ptr
    ├─ .Blob → ByteBlobLoader
    ├─ .File → FileReader
    ├─ .HTTPResponseSink → HTTPResponseSink
    └─ .NetworkSink → NetworkSink
```

### データフロー図

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

source             ───▶  ReadableStream
                         ├─ start()
                         └─ pull()
                                │
                                ▼
                         controller.enqueue()
                         └─ 内部キュー
                                │
                                ▼
                         reader.read()           ───▶   { value, done }
                         └─ チャンク取得

pipeTo:
ReadableStream     ───▶  パイプ処理              ───▶   WritableStream
                         └─ バックプレッシャー制御

tee:
ReadableStream     ───▶  ReadableStream.tee()    ───▶   [stream1, stream2]
                         └─ ストリーム分岐
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| streams.zig | `src/bun.js/webcore/streams.zig` | ソース | Start union、共通定義 |
| ReadableStream.zig | `src/bun.js/webcore/ReadableStream.zig` | ソース | ReadableStream実装 |
| Sink.zig | `src/bun.js/webcore/Sink.zig` | ソース | シンク共通インターフェース |
| FileSink.zig | `src/bun.js/webcore/FileSink.zig` | ソース | ファイルシンク |
| ByteBlobLoader.zig | `src/bun.js/webcore/ByteBlobLoader.zig` | ソース | Blobローダー |
| ByteStream.zig | `src/bun.js/webcore/ByteStream.zig` | ソース | バイトストリーム |
| ResumableSink.zig | `src/bun.js/webcore/ResumableSink.zig` | ソース | 再開可能シンク |
| streams.classes.zig | `src/bun.js/api/streams.classes.zig` | ソース | ストリームクラス定義 |
