# 機能設計書 42-wasi

## 概要

本ドキュメントは、Node.jsの`wasi`モジュールの機能設計を記載する。WASI（WebAssembly System Interface）は、WebAssemblyモジュールがOSレベルの機能（ファイルシステム、環境変数など）に安全かつポータブルにアクセスするための標準APIである。

### 本機能の処理概要

wasiモジュールは、Node.js環境でWebAssemblyモジュールを実行し、そのモジュールがファイルシステムや環境変数などのシステムリソースにアクセスできるようにするためのインターフェースを提供する。WASIは、WebAssemblyをブラウザ外で実行するための重要な基盤技術である。

**業務上の目的・背景**：WebAssemblyは元来ブラウザ向けに設計されたが、サーバーサイドやエッジコンピューティングでの利用ニーズが増加している。しかしWebAssemblyは本質的にサンドボックス化されており、ファイルアクセスやネットワーク通信などのシステム機能を直接利用できない。WASIはこの制約を解決し、WebAssemblyモジュールが安全かつ制御された方法でシステムリソースにアクセスできるようにする。これにより、C/C++/Rustなどで書かれたコードをWebAssemblyにコンパイルし、Node.jsで実行できるようになる。

**機能の利用シーン**：
- C/C++/Rustで書かれたネイティブライブラリのNode.jsへの移植
- セキュアなサンドボックス環境でのコード実行
- ポータブルなバイナリ配布
- エッジコンピューティングやサーバーレス環境での軽量ランタイム

**主要な処理内容**：
1. WASIインスタンスの生成とオプション設定
2. WebAssemblyモジュールへのWASI APIのインポート提供
3. WebAssemblyインスタンスの開始または初期化
4. ファイルシステムのプレオープン（サンドボックス化されたアクセス）
5. 標準入出力のリダイレクト
6. 環境変数の受け渡し

**関連システム・外部連携**：
- WebAssembly API（`WebAssembly.instantiate`など）
- ファイルシステム（preopensで指定されたディレクトリのみアクセス可能）
- uvwasi（C++バインディング経由のWASI実装）

**権限による制御**：
- preopensで指定されたディレクトリのみファイルアクセスが許可される
- 環境変数は明示的に渡されたもののみアクセス可能
- 標準入出力は指定されたファイルディスクリプタにマップされる

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングに該当なし |

## 機能種別

ランタイム環境 / システムインターフェース

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| options.version | String | Yes | WASIバージョン（'unstable'または'preview1'） | 'unstable'/'preview1'のみ |
| options.args | Array<String> | No | コマンドライン引数 | 配列であること |
| options.env | Object | No | 環境変数のキーバリューペア | オブジェクトであること |
| options.preopens | Object | No | 仮想パスから実際のパスへのマッピング | オブジェクトであること |
| options.stdin | Number | No | 標準入力のファイルディスクリプタ | 0以上の整数、デフォルト0 |
| options.stdout | Number | No | 標準出力のファイルディスクリプタ | 0以上の整数、デフォルト1 |
| options.stderr | Number | No | 標準エラーのファイルディスクリプタ | 0以上の整数、デフォルト2 |
| options.returnOnExit | Boolean | No | proc_exit時に例外ではなく終了コードを返す | デフォルトtrue |

### 入力データソース

JavaScriptコード内からの直接呼び出し、WebAssemblyバイナリ（.wasmファイル）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| wasiImport | Object | WebAssemblyインスタンス化時に渡すインポートオブジェクト |
| exitCode | Number | start()メソッドの戻り値（proc_exitの終了コード） |

### 出力先

呼び出し元への戻り値、標準出力/エラー出力

## 処理フロー

### 処理シーケンス

```
1. WASIインスタンスの生成
   └─ オプションのバリデーション
   └─ uvwasiの初期化
   └─ wasiImportオブジェクトの作成
2. WebAssemblyモジュールのロード
   └─ .wasmファイルの読み込み
   └─ WebAssembly.compile()
3. WebAssemblyインスタンス化
   └─ wasi.getImportObject()でインポート取得
   └─ WebAssembly.instantiate()
4. WASI実行開始
   └─ wasi.start(instance) または wasi.initialize(instance)
   └─ メモリの設定
   └─ _start()または_initialize()の呼び出し
5. proc_exit処理
   └─ returnOnExit=trueなら終了コードを返却
   └─ returnOnExit=falseなら例外をスロー
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[new WASI options]
    B --> C{version有効?}
    C -->|No| D[ERR_INVALID_ARG_VALUE]
    C -->|Yes| E[uvwasi初期化]
    E --> F[wasiImport生成]
    F --> G[WebAssembly.compile]
    G --> H[wasi.getImportObject]
    H --> I[WebAssembly.instantiate]
    I --> J{start or initialize?}
    J -->|start| K[finalizeBindings]
    J -->|initialize| L[finalizeBindings]
    K --> M{_start存在?}
    M -->|No| N[エラー]
    M -->|Yes| O[_start実行]
    L --> P{_initialize存在?}
    P -->|Yes| Q[_initialize実行]
    P -->|No| R[スキップ]
    O --> S{proc_exit?}
    S -->|Yes| T{returnOnExit?}
    T -->|Yes| U[終了コード返却]
    T -->|No| V[例外スロー]
    S -->|No| W[正常終了]
    Q --> W
    R --> W
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | バージョン指定必須 | versionオプションは必須で'unstable'か'preview1'のみ | インスタンス生成時 |
| BR-02 | 一度のみ開始可能 | start/initializeは1回のみ呼び出し可能 | 実行時 |
| BR-03 | 排他的エクスポート | _startと_initializeは排他的（両方存在不可） | start時 |
| BR-04 | preopensによるサンドボックス | 明示的にマップされたディレクトリのみアクセス可能 | ファイルアクセス時 |

### 計算ロジック

特になし

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

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ERR_INVALID_ARG_VALUE | 引数エラー | 無効なversionオプション | 'unstable'または'preview1'を指定 |
| ERR_WASI_ALREADY_STARTED | 状態エラー | 2回目のstart/initialize呼び出し | 新しいWASIインスタンスを生成 |
| TypeError | 型エラー | _startが関数でない | WebAssemblyモジュールの確認 |
| TypeError | 型エラー | _initializeが定義されているのにstartを呼び出し | initializeを使用 |

### リトライ仕様

リトライ不要（状態エラーは再試行しても解決しない）

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

該当なし

## パフォーマンス要件

- WebAssemblyの実行速度はネイティブに近い
- 初期化時のオーバーヘッドはuvwasiの初期化コスト

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

- **実験的機能**：セキュリティレビューが完了していない可能性
- **サンドボックス**：preopensで明示的に許可されたディレクトリのみアクセス可能
- **環境変数**：明示的に渡された環境変数のみWASMモジュールからアクセス可能
- **パーミッションシステム**：Node.jsのパーミッションシステムとの連携

## 備考

- 実験的機能のため、起動時に警告が発行される
- 将来のバージョンで仕様変更の可能性あり
- `--experimental-wasi-unstable-preview1`フラグなしで利用可能（警告あり）

---

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

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

### 推奨読解順序

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

WASIクラスの内部状態と設定オプションを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | wasi.js | `lib/wasi.js` | 29-33行目のSymbol定義（内部状態管理用） |
| 1-2 | wasi.js | `lib/wasi.js` | 38-110行目のコンストラクタ（オプション処理） |

**読解のコツ**: `kExitCode`, `kSetMemory`, `kStarted`, `kInstance`, `kBindingName`の各Symbolが何を管理しているか把握することが重要。これらはWASIインスタンスの内部状態を表す。

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

WASIクラスのpublicメソッドを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | wasi.js | `lib/wasi.js` | 166行目のmodule.exports |
| 2-2 | wasi.js | `lib/wasi.js` | 129-146行目のstart()メソッド |
| 2-3 | wasi.js | `lib/wasi.js` | 149-159行目のinitialize()メソッド |
| 2-4 | wasi.js | `lib/wasi.js` | 161-163行目のgetImportObject()メソッド |

**主要処理フロー**:
1. **129-130行目**: finalizeBindingsでインスタンスとメモリをセットアップ
2. **132-135行目**: _startと_initializeのエクスポートを取得・検証
3. **137-143行目**: _start()を呼び出し、proc_exit例外をキャッチ
4. **145行目**: 終了コードを返却

#### Step 3: バインディング初期化処理を理解する

finalizeBindingsメソッドの実装を読む。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | wasi.js | `lib/wasi.js` | 112-126行目のfinalizeBindings()メソッド |

**主要処理フロー**:
- **115-117行目**: 既に開始済みならエラー
- **119-120行目**: instanceとinstance.exportsのバリデーション
- **122行目**: kSetMemoryでWebAssemblyメモリを設定
- **124-125行目**: インスタンスと開始フラグを設定

#### Step 4: コンストラクタの処理を理解する

オプションの処理とuvwasiの初期化を詳細に読む。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | wasi.js | `lib/wasi.js` | 38-110行目のconstructor |

**主要処理フロー**:
- **42-57行目**: versionオプションの検証とバインディング名の設定
- **59-72行目**: args、env、preopensオプションの処理
- **84-88行目**: stdin、stdout、stderrの設定
- **90行目**: uvwasiラッパーの初期化
- **92-94行目**: 各メソッドのthisバインド
- **96-102行目**: returnOnExitオプションの処理
- **104-109行目**: 内部状態の初期化

#### Step 5: proc_exit処理を理解する

returnOnExit時の終了処理を読む。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | wasi.js | `lib/wasi.js` | 169-176行目のwasiReturnOnProcExit関数 |

**主要処理フロー**:
- **174行目**: 終了コードをkExitCodeに保存
- **175行目**: kExitCodeシンボルをスローして実行を中断

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

```
new WASI(options)
    │
    ├─ validateObject(options)
    ├─ validateString(options.version)
    │      └─ internalBinding('wasi')  // C++バインディング取得
    ├─ validateArray(options.args)
    ├─ validateObject(options.env)
    ├─ validateObject(options.preopens)
    ├─ validateInt32(stdin/stdout/stderr)
    └─ new _WASI(args, env, preopens, stdio)  // uvwasi初期化

wasi.start(instance)
    │
    ├─ finalizeBindings(instance)
    │      ├─ validateObject(instance)
    │      ├─ kSetMemory(memory)  // メモリ設定
    │      └─ kStarted = true
    │
    ├─ validateFunction(_start)
    ├─ validateUndefined(_initialize)
    └─ _start()
           └─ wasiReturnOnProcExit(rval)  // proc_exit時
                  └─ throw kExitCode

wasi.getImportObject()
    │
    └─ { [kBindingName]: wasiImport }
           // 'wasi_unstable' or 'wasi_snapshot_preview1'
```

### データフロー図

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

options                   ┌───────────────────────┐
{version, args,      ───▶│  new WASI(options)    │
 env, preopens}           │  ├─ バリデーション     │
                          │  └─ uvwasi初期化      │───▶  WASIインスタンス
                          └───────────────────────┘

.wasmバイナリ             ┌───────────────────────┐
                     ───▶│  WebAssembly.compile  │───▶  WebAssembly.Module

wasi.getImportObject() ──▶┌───────────────────────┐
WebAssembly.Module    ───▶│  WebAssembly.         │───▶  WebAssembly.Instance
                          │  instantiate          │
                          └───────────────────────┘

WebAssembly.Instance  ───▶┌───────────────────────┐
                          │  wasi.start(instance) │
                          │  ├─ finalizeBindings  │
                          │  └─ _start()呼び出し  │───▶  終了コード (Number)
                          └───────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| wasi.js | `lib/wasi.js` | ソース | WASIクラスの主要実装 |
| node_wasi.cc | `src/node_wasi.cc` | C++ソース | uvwasiへのC++バインディング |
| node_wasi.h | `src/node_wasi.h` | C++ヘッダ | WASIクラスの宣言 |
| validators.js | `lib/internal/validators.js` | ソース | 入力バリデーション関数 |
| errors.js | `lib/internal/errors.js` | ソース | エラーコード定義 |
