アーキテクチャ
ActivityPlug はポータブルなプロダクト契約を、リモート API マッピングと 配信トランスポートから分離します。アダプタが提供する同一のサービス動作を、TypeScript クライアント、 サーバの HTTP・GraphQL API、ブラウザ境界のいずれからも呼び出せます。
パッケージレイヤ
リポジトリは以下のレイヤで構成されます。
@activityplug/coreは正規化エンティティ、アダプタとクライアントの 契約、認証、capability、不透明 ID、ページネーション、エラー、リモート 権限、予算、ストリーム型を定義します。- アダプタパッケージは
ActivityPlugAdapterを実装します。Mastodon、 Pleroma/Akkoma、Hollo は@activityplug/mastodon-baseを共有し、 Misskey と HackersPub はそれぞれ独自の API をマッピングします。 @activityplug/serverはアダプタを選択し、HTTP、GraphQL、 WebSocket、オプションのブラウザ route を通じてサービスを公開します。@activityplug/session-postgresと@activityplug/session-redisは 共有または永続的なセキュリティ状態を必要とする配備向けにサーバ ストレージ契約を実装します。- サンプルパッケージはライブラリ、プロキシクライアント、ブラウザ クライアントの統合経路を実行します。フィクスチャパッケージは非公開の 開発支援であり、アプリケーションのランタイム依存関係ではありません。
コアパッケージはアダプタやサーバに依存しません。アダプタはコア契約に 依存します。サーバは具象アダプタに依存し、コアを peer dependency として受け入れる ため、利用側のワークスペースで公開契約のインスタンスが 1 つに保たれ ます。
ライブラリのリクエストフロー
ライブラリの呼び出し元はアダプタ、インスタンス origin、オプションの セッションストア、リモート権限、capability セット、予算ファクトリから クライアントを作成します。各サービス呼び出しは以下の順で処理されます。
- クライアントは入力、必須 capability、セッション対象、不透明 ID、 ページカーソル、ポータブルな制限を検証します。
- アダプタ操作を解決し、正規 origin、アダプタ ID、操作、capability、 スコープ制限付き fetch、セッションストア、検出済みソフトウェア、 オプションの予算を含む
AdapterOperationContextを構築します。 - アダプタは正規化された入力をリモートリクエストに変換し、スコープ 制限付き fetch で実行します。
- アダプタはレスポンスを検証し、正規化エンティティ、コネクション、 型付きエラーにマッピングします。
- クライアントはポータブルな結果を返します。リモートペイロードを
rawに残せますが、呼び出し元はその形式がすべてのアダプタで共通 だと想定できません。
クライアントがグローバル fetch にフォールバックすることはありません。 RemoteAuthority がなければ、リモート操作はネットワーク I/O の前に ORIGIN_NOT_ALLOWED で失敗します。
サーバのリクエストフロー
createActivityPlugServer() は Node.js ランタイムを組み立てます。審査 済みの外向き fetch 境界を 1 つ作成し、設定済みアダプタを ActivityPlugApiService に結び付け、公開アプリケーションをマウントします。
公開アプリケーションは以下を提供します。
- JSON または multipart 入力を受け取る HTTP ルート
- 同じサービスメソッド上に構築された GraphQL エンドポイント
- HTTP サーフェス用の OpenAPI メタデータ
- ストリーミング操作用の WebSocket アップグレード
- ヘルスチェックと readiness 動作
HTTP と GraphQL は同じサービス契約のトランスポートマッピングです。 それぞれが独立してリモート API を呼び出すことはありません。リクエスト 中断シグナル、入力制限、GraphQL 複雑度制限、認証、capability チェック、 ActivityPlugError のシリアライズは各境界で適用されます。
サーバは選択したアダプタと origin ごとに操作スコープのクライアントを 1 つ作成します。そのリモート権限はサーバの origin ポリシ、固定 DNS ディスパッチ、プライベートネットワーク設定、credential 許可範囲、 リクエスト制限を使います。アダプタが配備環境の外向きポリシを迂回する ことはできません。
ブラウザ境界
ブラウザオプションが指定されると、サーバは公開ルートより前に /v1/browser/* をマウントします。この境界はブラウザ向けバックエンド サーフェスです。
- ブラウザセッションは署名済みセキュア cookie に保持されます。
- 状態を変更するリクエストには設定済み CSRF ヘッダが必要です。
- ブラウザ route は
AuthorizationヘッダとsessionIdクエリ パラメータを拒否します。 - サーバはブラウザセッションを ActivityPlug 認証セッションとして 解決し、HTTP・GraphQL と同じ API サービスを呼び出します。
- 有効期間が短く 1 回限りのチケットが、ActivityPlug セッション ID を URL に含めずにブラウザの WebSocket アップグレードを認可します。
ブラウザ境界は独立したブラウザセッションと一時状態を持ちつつ、リモート credential にはアダプタの認証セッションを再利用します。
認証とストレージ
アダプタの認証ストラテジはトークンセットをコア認証サービスに返します。 サービスはトークンセットを StoredAuthSession レコードとして保存し、 機密情報を除去した AuthSession を呼び出し元に返します。変更操作は リビジョンチェックを使うため、同時に実行された検証・更新・失効・消費が 互いの変更を無通知で上書きすることはありません。
サーバは複数のセキュリティ状態契約を調整します。
- 認証セッション
- credential リースと OAuth クライアントシークレット
- ブラウザセッション
- OAuth コールバック state と認証チャレンジ
- OAuth 開始時のレート制限
- ストリームチケット
インメモリ実装はプロセス内に限定されます。PostgreSQL パッケージと Redis パッケージはセッションストレージに記載された 本番向けストレージ契約に対応します。SecurityStateLifecycle はストアを 初期化し、バックエンドが定期的なスキャンを要求する場合は期限切れ項目を 削除し、所有するリソースを閉じます。
Capability と検出
静的なアダプタメタデータが最初の互換性契約です。インスタンス検出では NodeInfo、OAuth、インスタンスエンドポイント、プローブによる判定を追加 できます。capability を統合する際は最終判定のソース、理由、オプションの 制約が保持されます。
クライアントとサーバはどちらも公開操作の境界で capability を適用します。 アダプタにメソッドが存在するだけでは不十分です。検出したソフトウェアや バージョンに依存する操作は、capability 判定で許可されるまで利用 できません。
識別子とページネーション境界
アダプタはリモート ID とカーソルを使います。公開トランスポートは ActivityPlug の不透明な値を使います。エンティティ ID とページカーソルは 異なる変換境界を通過します。
- クライアントはエンティティ ID のアダプタ、origin、エンティティ型を 検証し、デコードした raw ID をアダプタに渡します。
- リモートのページネーション契約はアダプタが所有するため、アダプタは アダプタ ID、origin、正確な公開操作を含めてページカーソルを エンコード・デコードします。
- アダプタのマッピングは、結果がアダプタレイヤを出る前に正規化された エンティティ参照を作成します。
この設計により、呼び出し元が誤って Mastodon の ID を Misskey アダプタに 送ったり、別のエンドポイントでカーソルを再利用したりすることを防ぎます。 raw 識別子は診断と明示的な相互運用のために引き続き参照できます。
ストリーミングフロー
ストリームは AsyncIterable<StreamEvent> を返します。アダプタはリモート の WebSocket プロトコルをタイムライン、通知、削除、編集、フィルタ変更、 ハートビートのイベントに変換します。
ストリーミングを行うアダプタには注入された WebSocketFactory が必要です。 サーバは接続先を固定する Node.js 実装を提供します。ファクトリは信頼済み の公開操作と、プロトコルが許可する場合は認証値を受け取ります。共有コア ユーティリティはファクトリの起動時間とキュー内イベント数を制限し、 キャンセル後に遅着したソケットを閉じます。
拡張境界
新しいサーバファミリはコアやトランスポートレイヤにリモートサービス固有の 条件分岐を追加するのではなく、アダプタとして追加してください。新しい配信 サーフェスは ActivityPlugApiService 上に追加し、同じ正規化と capability 動作を継承させてください。ストレージバックエンドは公開済みのストア契約を 実装して追加し、公開セッションを通じてバックエンドのハンドルを公開しない でください。