FAQ
繋ぎ屋に関するよくある質問と回答です。
Q1. 未登録 URL に接続したらどうなる?
pool.relay() で登録していない URL に new WebSocket() すると、接続失敗として扱われます。onerror イベント → onclose イベント(code: 1006)が発火します。実際のリレーに接続できなかった場合と同じ動作です。
Q2. 複数リレーの追加方法は?
pool.relay() を URL ごとに呼び出します。各リレーは完全に独立して動作します。
Q3. テストが遅い場合の対処法は?
- レイテンシを 0 にする(デフォルト)。速度テスト以外では
latencyを設定しない - streamEvents の interval を短くする(10ms 程度)
- 独立したテストは並行実行する
pool.reset()で状態をクリアしてインスタンスを再利用
詳しくは パフォーマンスガイド を参照。
Q4. 実際の暗号署名は検証される?
いいえ。繋ぎ屋はモックライブラリなので、id, pubkey, sig の暗号的検証は行いません。EventBuilder が生成するのもランダムな hex 文字列です。署名検証のテストが必要な場合は、onEVENT ハンドラー内で独自に実装してください。
Q5. Deno 以外のランタイム(Node.js, Bun)で使える?
はい。npm パッケージ(@ikuradon/tsunagiya)として公開しているため、npm install でそのまま使えます。Vitest, Jest 等のテストフレームワークでも動作します。
npm install @ikuradon/tsunagiyav0.2.0 以降では、以下の主要 Nostr クライアントライブラリとの互換性を E2E テストで検証しています:
- nostr-tools - SimplePool での REQ/EVENT 処理
- NDK - NDK インスタンス経由のイベント取得・投稿
- rx-nostr - RxNostr の Reactive API(createRxNostr / use)
- nostr-fetch - NostrFetcher によるイベント取得(fetch / iterator)
Vitest での使い方は はじめに を参照してください。
Q6. テストフレームワーク依存はある?
ありません。Deno.test に加えて、任意のテストフレームワークで使用できます。@ikuradon/tsunagiya/testing のアサーション関数は throw Error でフレームワーク非依存です。
Q7. onREQ を設定すると store() のイベントは使われない?
はい。onREQ ハンドラーを設定すると、自動フィルタリング(store 内のイベント検索)はスキップされ、ハンドラーの戻り値だけが使われます。両方使いたい場合は、ハンドラー内で手動フィルタリングしてください。
Q8. 同じ URL に対して pool.relay() を複数回呼んだらどうなる?
2回目以降は既存のインスタンスが返されます。オプションは最初の呼び出し時のものが使われます。
Q9. EVENT メッセージの OK レスポンスをカスタマイズするには?
onEVENT ハンドラーを使います。
Q10. AUTH のチャレンジ文字列を取得するには?
onmessage で ["AUTH", challenge] メッセージを受信します。
Q11. スナップショットにはハンドラーや接続状態も含まれる?
いいえ。スナップショットに含まれるのは ストア内のイベント と 受信メッセージログ だけです。onREQ, onEVENT ハンドラーや接続状態は保存・復元されません。
Q12. reset() と restore() の違いは?
reset(): 完全にクリア(ストア、受信ログ、ハンドラー、AUTH 状態)restore(): スナップショット時点の ストアと受信ログ に戻す。ハンドラーは変更しない
Q13. バイナリメッセージは送信できる?
MockWebSocket は文字列メッセージのみ対応です。ArrayBuffer, Blob 等を send() すると Error がスローされます。Nostr プロトコルは JSON 文字列ベースなので、通常は問題ありません。
Q14. テスト中に globalThis.WebSocket を直接使いたい場合は?
pool.install() 後は全ての new WebSocket() が MockWebSocket になります。一部だけ実際の WebSocket を使いたい場合は、install 前に参照を保存してください。
Q15. 外部依存はある?
ゼロです。繋ぎ屋は外部パッケージに一切依存しません。テストモジュールの @std/assert は繋ぎ屋自体のテスト用であり、ライブラリとしての依存ではありません。
Q16. CI で使うときの注意点は?
特別な設定は不要です。globalThis.WebSocket の差し替えはプロセス内で完結するため、ネットワークアクセスも不要です。--allow-net フラグなしで動作します。
Q17. EventBuilder で生成されるイベントのフィールド値は?
未登録 URL への接続:
pool.relay("wss://known.relay.test"); // これだけ登録
const ws = new WebSocket("wss://unknown.relay.test"); // → エラー + close(1006)複数リレーの追加:
const pool = new MockPool();
const relay1 = pool.relay("wss://relay1.example.com");
const relay2 = pool.relay("wss://relay2.example.com");
const relay3 = pool.relay("wss://relay3.example.com");onEVENT でのカスタムレスポンス:
relay.onEVENT((event) => {
if (event.kind === 1) {
return ["OK", event.id, true, ""];
}
return ["OK", event.id, false, "blocked: kind not allowed"];
});AUTH チャレンジの取得:
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
if (msg[0] === "AUTH") {
const challenge = msg[1]; // チャレンジ文字列
}
};同一 URL への複数回呼び出し:
const r1 = pool.relay("wss://relay.example.com", { latency: 100 });
const r2 = pool.relay("wss://relay.example.com"); // r1 と同一インスタンス
console.log(r1 === r2); // trueglobalThis.WebSocket を直接使いたい場合:
const RealWebSocket = globalThis.WebSocket;
pool.install();
// new WebSocket() は MockWebSocket
// new RealWebSocket() は本物の WebSocketEventBuilder のデフォルトフィールド値:
| フィールド | デフォルト値 |
|---|---|
id | ランダム 64 文字 hex |
pubkey | ランダム 64 文字 hex |
created_at | 現在時刻(UNIX 秒) |
kind | ファクトリメソッドによる |
tags | [] |
content | "" |
sig | ランダム 128 文字 hex |
コード例(各 Q&A)
詳細なコード例は 使用例集 および チュートリアル を参照してください。
関連ドキュメント
- チュートリアル — 基本的な使い方
- トラブルシューティング — エラー解決
- API リファレンス — API 詳細