# セッション管理 (SessionProvider)

`SessionProvider`は`@arcblock/did-connect-react`ライブラリの礎です。これは、セッション関連のすべてのロジック、状態、アクションをカプセル化するReact Context Providerです。アプリケーションを`SessionProvider`でラップすることにより、propsを手動で下に渡すことなく、アプリケーションツリー内のどのコンポーネントでもユーザーのセッション情報と認証メソッドを利用できるようになります。

このコンポーネントは、セッショントークンの保存やユーザーデータの管理から、ログイン/ログアウトフローの調整、セッションの自動更新まで、すべてを処理します。

## 仕組み

`SessionProvider`は、現在のユーザーの状態（`user`オブジェクト、`loading`ステータスなど）を保持するセッションコンテキストを作成し、その状態を変更する関数（例：`login`、`logout`）を提供します。`SessionProvider`内にネストされたどのコンポーネントも、このコンテキストを購読してこのデータにアクセスし、認証アクションをトリガーできます。

以下は、基本的なアーキテクチャを示す図です。

<!-- DIAGRAM_IMAGE_START:architecture:4:3:1765962229 -->
![Session Management (SessionProvider)](assets/diagram/core-components-session-provider-01.ja.jpg)
<!-- DIAGRAM_IMAGE_END -->

## はじめに

セッション管理機能を使用するには、まず`SessionProvider`をインポートしてアプリケーションをラップする必要があります。このライブラリは、設定済みのプロバイダーを作成するためのファクトリー関数をエクスポートします。

### 基本的なセットアップ

プロバイダーをセットアップする最も一般的な方法は、`createAuthServiceSessionContext`を使用することです。これは、ArcBlockエコシステム（Blocklets）内で実行されるアプリケーション向けに事前設定されています。

```javascript App.js icon=logos:javascript
import React from 'react';
import { createAuthServiceSessionContext } from '@arcblock/did-connect-react/lib/Session';
import AuthButton from './AuthButton';

// SessionProviderとコンテキストにアクセスするためのフックを作成
const { SessionProvider, SessionContext } = createAuthServiceSessionContext();

export const useSession = () => React.useContext(SessionContext);

export default function App() {
  return (
    <SessionProvider>
      <div className="App">
        <h1>Welcome to DID Connect</h1>
        <AuthButton />
      </div>
    </SessionProvider>
  );
}
```

```javascript AuthButton.js icon=logos:javascript
import React from 'react';
import { useSession } from './App';

export default function AuthButton() {
  const { session } = useSession();

  if (session.loading) {
    return <div>Loading...</div>;
  }

  if (session.user) {
    return (
      <div>
        <p>Welcome, {session.user.fullName || session.user.did}</p>
        <button onClick={() => session.logout()}>Logout</button>
      </div>
    );
  }

  return <button onClick={() => session.login()}>Login</button>;
}
```

この例では、`createAuthServiceSessionContext`が`SessionProvider`を生成します。`App`をそれでラップすると、`AuthButton`のような子コンポーネントは、`useSession`フックを使用してセッションデータと関数にアクセスできるようになります。

## SessionProviderのProps

`SessionProvider`の動作は、さまざまなpropsを渡すことで設定できます。

<x-field-group>
  <x-field data-name="serviceHost" data-type="string" data-desc="認証サービスバックエンドのベースURL。デフォルトは現在のBlockletのプレフィックスまたは'/'です。"></x-field>
  <x-field data-name="autoConnect" data-type="boolean" data-default="false" data-desc="trueの場合、ページロード時にユーザーセッションが見つからないと、DID Connectダイアログが自動的に開きます。"></x-field>
  <x-field data-name="autoDisconnect" data-type="boolean" data-default="true" data-desc="trueの場合、アプリケーションIDがセッションクッキーに保存されているものと一致しない場合、セッションは自動的にクリアされます。"></x-field>
  <x-field data-name="protectedRoutes" data-type="string[]" data-default='["*"]' data-desc="保護するルートパターンの配列。未認証のユーザーがこれらのルートにアクセスしようとすると、セッションが解決されるまで読み込みスピナーが表示されます。ワイルドカード（*）がサポートされています。"></x-field>
  <x-field data-name="locale" data-type="string" data-desc="DID Connect UIの表示言語を設定します。デフォルトはブラウザの言語です。"></x-field>
  <x-field data-name="webWalletUrl" data-type="string" data-desc="接続プロセスで使用するウェブベースのDID WalletのURL。"></x-field>
  <x-field data-name="timeout" data-type="number" data-default="120000" data-desc="接続プロセス中にDID Walletからの応答を待つためのタイムアウト（ミリ秒単位）。"></x-field>
  <x-field data-name="useSocket" data-type="boolean" data-default="true" data-desc="ウォレットとのリアルタイム通信にWebSocketを使用するかどうかを決定し、より高速なユーザーエクスペリエンスを提供します。"></x-field>
  <x-field data-name="extraParams" data-type="object" data-desc="バックエンドへのすべての認証リクエストとともに送信される追加パラメーターのオブジェクト。"></x-field>
</x-field-group>

## セッションコンテキストオブジェクト

`SessionContext`を利用すると、セッションの状態とAPIを含むオブジェクトを取得できます。主要なプロパティは`session`で、これには対話するすべてのデータとメソッドが含まれています。

### 状態プロパティ

これらは、ユーザーセッションの現在の状態を記述する読み取り専用のプロパティです。

<x-field-group>
  <x-field data-name="user" data-type="User | null" data-desc="セッションが存在する場合、認証されたユーザーオブジェクト。それ以外の場合はnull。DID、名前、メール、アバターなどの詳細が含まれます。"></x-field>
  <x-field data-name="loading" data-type="boolean" data-desc="セッションが初期化中、更新中、またはログイン/ログアウトプロセス中である場合はtrue。"></x-field>
  <x-field data-name="initialized" data-type="boolean" data-desc="ページロード時に最初のセッションチェックが完了するとtrueになります。"></x-field>
  <x-field data-name="open" data-type="boolean" data-desc="DID Connectダイアログが現在開いている場合はtrue。"></x-field>
  <x-field data-name="error" data-type="string" data-desc="最後のセッション操作が失敗した場合、エラーメッセージが含まれます。"></x-field>
  <x-field data-name="provider" data-type="string" data-desc="最後のログインに使用されたプロバイダー（例：'wallet'、'github'、'google'）。"></x-field>
  <x-field data-name="walletOS" data-type="string" data-desc="接続されたDID Walletのオペレーティングシステム（例：'ios'、'android'、'web'）。"></x-field>
  <x-field data-name="unReadCount" data-type="number" data-desc="現在のユーザーの未読通知の数。"></x-field>
</x-field-group>

### アクションメソッド

これらは、認証フローを開始したり、セッションを管理したりするために呼び出すことができる関数です。

<x-field-group>
  <x-field data-name="login()" data-type="function">
    <x-field-desc markdown>DID Connect UIを開いてユーザーのログインプロセスを開始します。オプションのコールバックとパラメーターを受け入れます。</x-field-desc>
  </x-field>
  <x-field data-name="logout()" data-type="function">
    <x-field-desc markdown>現在のユーザーをログアウトさせ、ストレージからセッションをクリアします。完了時に実行されるオプションのコールバック関数を受け入れます。</x-field-desc>
  </x-field>
  <x-field data-name="switchDid()" data-type="function">
    <x-field-desc markdown>ログイン中のユーザーが別のアカウントに切り替えることを許可します。アカウント切り替え用のコンテキストでDID Connect UIを再度開きます。</x-field-desc>
  </x-field>
  <x-field data-name="bindWallet()" data-type="function">
    <x-field-desc markdown>ソーシャルプロバイダー（OAuth）またはパスキー経由でログインしたユーザーのために、この関数は既存のアカウントにDID Walletを接続するフローを開始します。</x-field-desc>
  </x-field>
  <x-field data-name="refresh()" data-type="function">
    <x-field-desc markdown>サーバーからユーザーのセッションデータを手動で更新します。更新されたプロフィール情報や権限を取得するのに便利です。</x-field-desc>
  </x-field>
  <x-field data-name="switchProfile()" data-type="function">
    <x-field-desc markdown>DID Connect UIを開き、ユーザーが同じDIDアカウント内の異なるプロフィール（例：個人用、仕事用）を切り替えられるようにします。</x-field-desc>
  </x-field>
  <x-field data-name="switchPassport()" data-type="function">
    <x-field-desc markdown>DID Connect UIを開き、ユーザーが異なるパスポート（異なる資格情報や役割のセットを表す場合がある）を切り替えられるようにします。</x-field-desc>
  </x-field>
  <x-field data-name="connectToDidSpaceForFullAccess()" data-type="function">
    <x-field-desc markdown>ユーザーのDID Spaceへの接続を開始し、フルアクセス権限を要求します。これは、ユーザーの個人データストアにデータを読み書きする必要があるアプリケーションでしばしば必要とされます。</x-field-desc>
  </x-field>
  <x-field data-name="withSecondaryAuth()" data-type="function">
    <x-field-desc markdown>別の関数をラップする高階関数で、ラップされた関数が実行される前に、ユーザーが二次認証ステップ（例：パスワードの再入力、パスキーの使用）を完了する必要があります。これは機密性の高いアクションを保護するのに理想的です。</x-field-desc>
  </x-field>
</x-field-group>

### イベントの購読

コンテキストは`events`オブジェクトも提供します。これは`EventEmitter3`のインスタンスです。これを使用して、セッションのさまざまなライフサイクルイベントを購読できます。

```javascript EventListener.js icon=logos:javascript
import React, { useEffect } from 'react';
import { useSession } from './App';

function EventListener() {
  const { events } = useSession();

  useEffect(() => {
    const handleLogin = (result) => {
      console.log('User logged in:', result.user.did);
    };

    const handleLogout = () => {
      console.log('User logged out');
    };

    events.on('login', handleLogin);
    events.on('logout', handleLogout);

    // コンポーネントのアンマウント時にリスナーをクリーンアップ
    return () => {
      events.off('login', handleLogin);
      events.off('logout', handleLogout);
    };
  }, [events]);

  return null; // このコンポーネントは何もレンダリングしません
}
```

利用可能なイベントには、`login`、`login-failed`、`logout`、`change`、`bind-wallet`、`switch-passport`などがあります。

## 高度なカスタマイズ

異なるストレージメカニズムやより詳細な制御が必要なシナリオでは、汎用の`createSessionContext`ファクトリーを使用できます。

```javascript customSession.js icon=logos:javascript
import { createSessionContext } from '@arcblock/did-connect-react/lib/Session';

const { SessionProvider, SessionContext } = createSessionContext(
  'my_app_session_token', // カスタムストレージキー
  'ls',                   // cookieの代わりにlocalStorageを使用
  {},
  {
    rolling: false,         // 自動トークン更新を無効化
  }
);

// ... 必要に応じてエクスポートして使用
```

これにより、ストレージエンジンを`localStorage`（'ls'）や`cookie`に変更したり、トークン更新ポリシーを調整したりするなど、セッションの動作を微調整できます。