# 機能設計書 41-npmレジストリ

## 概要

本ドキュメントは、Bunパッケージマネージャーのnpmレジストリ通信機能に関する設計書である。npmレジストリとの通信プロトコル、認証処理、パッケージメタデータの取得・解析について詳述する。

### 本機能の処理概要

npmレジストリ機能は、npmパッケージのメタデータ取得、tarball（パッケージアーカイブ）のダウンロード、認証処理、レジストリスコープの管理を行う中核機能である。

**業務上の目的・背景**：JavaScript/TypeScriptプロジェクトでは、npm（Node Package Manager）エコシステムに登録された数百万のパッケージを活用する。Bunが高速なパッケージ管理を提供するには、npmレジストリとの効率的な通信が不可欠である。この機能により、開発者は既存のnpmエコシステム全体を活用しながら、Bunの高速性能の恩恵を受けることができる。

**機能の利用シーン**：
- `bun install` 実行時のパッケージ情報取得
- `bun add <package>` での新規パッケージ追加時
- `bun update` でのバージョン確認時
- プライベートレジストリ（GitHub Packages、npmjs.com有料プラン等）へのアクセス時

**主要な処理内容**：
1. レジストリURLの解析とスコープ（@org/package形式）の判定
2. 認証情報（トークン、ユーザー名/パスワード）の取得と適用
3. HTTPリクエストの構築とパッケージメタデータ（manifest）の取得
4. レスポンスのパース（JSON形式）とバージョン情報の抽出
5. マニフェストキャッシュへの保存と再利用
6. whoami API による認証状態の確認

**関連システム・外部連携**：
- npmjs.org（デフォルトレジストリ）
- プライベートnpmレジストリ（Verdaccio、GitHub Packages、GitLab NPM等）
- .npmrc設定ファイル
- bunfig.toml設定ファイル

**権限による制御**：認証トークンまたはユーザー名/パスワードにより、プライベートパッケージへのアクセスが制御される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | x (bunx) | 補助機能 | パッケージ情報のnpmレジストリからの取得 |
| 6 | install | 主機能 | パッケージ情報とtarballのダウンロード |
| 7 | add | 主機能 | パッケージ情報の取得とダウンロード |
| 9 | update | 主機能 | 最新バージョン情報の取得 |
| 10 | audit | 補助機能 | 脆弱性データベースへの問い合わせ |
| 11 | outdated | 補助機能 | パッケージの最新バージョン情報取得 |
| 14 | publish | 主機能 | レジストリへのパッケージアップロード |
| 18 | info | 主機能 | レジストリからのパッケージメタデータ取得 |
| 22 | create | 補助機能 | テンプレートパッケージの取得 |

## 機能種別

データ連携（外部API通信）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| package_name | string | Yes | パッケージ名（スコープ付き可） | 有効なnpmパッケージ名形式 |
| registry_url | URL | No | レジストリURL | 有効なURL形式、デフォルトはhttps://registry.npmjs.org/ |
| token | string | No | 認証トークン | Bearer形式 |
| username | string | No | ユーザー名 | _password と併用 |
| password | string | No | パスワード（Base64） | username と併用 |
| scope | string | No | スコープ名（@orgなど） | @で始まる文字列 |

### 入力データソース

- bunfig.toml（レジストリ設定）
- .npmrc（npm互換の認証設定）
- 環境変数（NPM_TOKEN等）
- package.json（publishConfig）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| PackageManifest | struct | パッケージのメタデータ全体 |
| versions | map | 利用可能なバージョンとその詳細 |
| dist-tags | map | latest、next等のタグとバージョンのマッピング |
| dependencies | map | 各バージョンの依存関係 |
| integrity | string | パッケージのSHA512ハッシュ |
| tarball_url | string | パッケージアーカイブのダウンロードURL |

### 出力先

- メモリ内マニフェストキャッシュ
- ディスクキャッシュ（~/.bun/install/cache）
- 標準出力（エラーメッセージ）

## 処理フロー

### 処理シーケンス

```
1. レジストリURLの決定
   └─ スコープに対応するレジストリを検索、なければデフォルトを使用
2. 認証情報の取得
   └─ トークン、ユーザー名/パスワードを設定から取得
3. HTTPリクエストの構築
   └─ ヘッダー（Accept、Authorization、User-Agent）の設定
4. キャッシュの確認
   └─ ETag/Last-Modifiedによる条件付きリクエスト
5. レジストリへのリクエスト送信
   └─ GET /{package_name} または GET /{@scope}/{package_name}
6. レスポンスの処理
   └─ ステータスコードの確認、JSONパース
7. マニフェストの保存
   └─ キャッシュへの保存、有効期限の設定
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{スコープ付きパッケージ?}
    B -->|Yes| C[スコープ用レジストリを検索]
    B -->|No| D[デフォルトレジストリを使用]
    C --> E{レジストリ設定あり?}
    E -->|Yes| F[スコープ用レジストリを使用]
    E -->|No| D
    F --> G[認証情報を取得]
    D --> G
    G --> H{キャッシュあり?}
    H -->|Yes| I[条件付きリクエスト: If-None-Match]
    H -->|No| J[通常リクエスト]
    I --> K[HTTPリクエスト送信]
    J --> K
    K --> L{ステータスコード確認}
    L -->|304| M[キャッシュを使用]
    L -->|200| N[JSONパース]
    L -->|401/403| O[認証エラー]
    L -->|404| P[パッケージ未発見]
    L -->|5xx| Q[サーバーエラー]
    N --> R[マニフェストをキャッシュ]
    M --> S[終了: マニフェスト返却]
    R --> S
    O --> T[エラー終了]
    P --> T
    Q --> T
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-41-01 | スコープ優先 | @scope付きパッケージはスコープ設定のレジストリを優先使用 | パッケージ名が@で始まる場合 |
| BR-41-02 | 認証継承 | 親URLの認証設定を子パスにも適用 | レジストリURLが一致する場合 |
| BR-41-03 | キャッシュ有効期限 | マニフェストキャッシュは300秒（5分）有効 | ネットワークリクエスト時 |
| BR-41-04 | HTTPSアップグレード | HTTPのURLはHTTPSに自動アップグレード | セキュリティポリシー |

### 計算ロジック

キャッシュ有効期限の計算:
```
expiry_timestamp = current_timestamp + 300
```

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

本機能はデータベースを使用せず、ファイルシステムベースのキャッシュを使用する。

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

該当なし（キャッシュはファイルシステムに保存）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 400 | BadRequest | 不正なリクエスト形式 | リクエストパラメータを確認 |
| 401 | Unauthorized | 認証失敗 | トークンまたは資格情報を確認 |
| 403 | Forbidden | アクセス拒否 | 権限設定を確認 |
| 404 | NotFound | パッケージが存在しない | パッケージ名を確認 |
| 429 | TooManyRequests | レート制限超過 | 時間をおいて再試行 |
| 5xx | ServerError | サーバー側エラー | 時間をおいて再試行 |

### リトライ仕様

- HTTPエラー429、5xxの場合は自動リトライ
- 最大3回まで再試行
- 指数バックオフによる待機

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

HTTPリクエストは非トランザクション。キャッシュ書き込みはアトミックに実行（一時ファイル作成後にリネーム）。

## パフォーマンス要件

- マニフェスト取得: 通常500ms以内（ネットワーク状況による）
- キャッシュヒット時: 10ms以内
- 並列リクエスト対応（デフォルト最大16並列）

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

- 認証トークンはメモリ上でのみ保持、ログ出力時はマスク
- HTTPS通信を強制（HTTP URLは自動アップグレード）
- TLS証明書検証（NODE_TLS_REJECT_UNAUTHORIZED環境変数で制御可能）

## 備考

- npm registry API v1互換
- ETagベースのキャッシュ検証に対応
- gzip圧縮レスポンスの自動展開

---

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

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

### 推奨読解順序

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

npmレジストリ通信で使用されるデータ構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | npm.zig | `src/install/npm.zig` | Registry.Scope構造体で認証情報の保持方法を理解 |
| 1-2 | install.zig | `src/install/install.zig` | Features構造体でパッケージ取得オプションを理解 |

**読解のコツ**: Zigの構造体定義では、`pub const`で公開される型と`pub fn`で公開されるメソッドを区別して読む。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | npm.zig | `src/install/npm.zig` | Registry.getPackageMetadata関数が主要エントリーポイント |

**主要処理フロー**:
1. **393-464行目**: getPackageMetadata関数でHTTPレスポンスを処理
2. **404-413行目**: ステータスコード別の分岐処理
3. **440-461行目**: PackageManifest.parseでJSONをパース

#### Step 3: 認証処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | npm.zig | `src/install/npm.zig` | Registry.Scope.fromAPI関数で認証情報の構築を理解 |

**主要処理フロー**:
- **232-375行目**: fromAPI関数でレジストリ設定からScopeを構築
- **250-351行目**: トークン、ユーザー名/パスワードの抽出ロジック
- **274-276行目**: Bearer Token（_authToken）の処理

#### Step 4: whoami APIを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | npm.zig | `src/install/npm.zig` | whoami関数で認証状態確認の実装を理解 |

**主要処理フロー**:
- **8-146行目**: whoami関数でnpmレジストリの/-/whoami APIを呼び出し
- **29-57行目**: HTTPヘッダーの構築（Authorization、User-Agent等）
- **141-145行目**: JSONレスポンスからusernameを抽出

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

```
PackageManager (PackageManager.zig)
    │
    ├─ Npm.Registry.getPackageMetadata (npm.zig)
    │      │
    │      ├─ PackageManifest.parse
    │      └─ PackageManifest.Serializer.saveAsync
    │
    ├─ Npm.Registry.Scope.fromAPI (npm.zig)
    │      └─ URL解析、認証情報抽出
    │
    └─ Npm.whoami (npm.zig)
           └─ HTTP GET /-/whoami
```

### データフロー図

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

package_name ────────▶ Registry.Scope決定 ─────────▶ HTTPリクエスト構築
                              │
registry_url ─────────▶       │
                              ▼
auth_token ───────────▶ HTTPリクエスト送信 ─────────▶ レスポンス受信
                              │
                              ▼
                      JSONパース ─────────────────▶ PackageManifest
                              │
                              ▼
                      キャッシュ保存 ───────────────▶ ディスクキャッシュ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| npm.zig | `src/install/npm.zig` | ソース | npmレジストリ通信の中核実装 |
| install.zig | `src/install/install.zig` | ソース | インストール機能の統合、Features定義 |
| PackageManager.zig | `src/install/PackageManager.zig` | ソース | パッケージマネージャー全体の制御 |
| NetworkTask.zig | `src/install/NetworkTask.zig` | ソース | HTTPリクエストの非同期実行 |
| PackageManifestMap.zig | `src/install/PackageManifestMap.zig` | ソース | マニフェストキャッシュ管理 |
| extract_tarball.zig | `src/install/extract_tarball.zig` | ソース | tarballの展開処理 |
