NIP-10: テキストノートのスレッディング
NIP-10は、kind 1 noteが互いを参照してreply threadを作る方法を定めます。conversation viewを正しく構築するには、これを理解している必要があります。
仕組み
誰かがnoteへ返信するとき、clientは次を知る必要があります。これは何へのreplyか。会話のrootは何か。誰へ通知すべきか。NIP-10は、e tag(event reference)とp tag(pubkey mention)を通じてこれに答えます。
Marked Tags(推奨)
現在のclientは、e tag内で明示的なmarkerを使います。
{
"id": "f9c2e...",
"pubkey": "a3b9c...",
"created_at": 1734912345,
"kind": 1,
"tags": [
["e", "abc123...", "wss://relay.example.com", "root"],
["e", "def456...", "wss://relay.example.com", "reply"],
["p", "91cf9..."],
["p", "14aeb..."]
],
"content": "Great point! I agree.",
"sig": "b7d3f..."
}
root markerはthreadを始めた元noteを指します。reply markerは、いま返答している特定のnoteを指します。rootへ直接replyする場合は、rootだけを使います(reply tagは不要です)。この区別はrenderingに重要です。replyはthread viewでのindentationを決め、rootはすべてのreplyを同じthreadとして束ねます。
Threading Rules
- Direct reply to root:
rootmarker付きのetagが1つ - Reply to a reply:
rootとreplyのetagが2つ rootはthread全体で変わらず、replyは返答対象に応じて変わる
Notifications and Mentions
通知すべき全員のp tagを含めます。最低限、返信先noteのauthorはtag付けする必要があります。慣例として、親eventに入っていたp tagをすべて引き継ぎ、会話参加者を取りこぼさないようにします。さらに、content内で@mentionしたユーザーも含めます。
Relay Hints
e tagとp tagの3番目の位置には、そのeventやユーザーのcontentが見つかる可能性があるrelay URLを入れられます。これにより、元のrelayへ接続していなくても、参照先contentを取得しやすくなります。
相互運用メモ
初期のNostr実装は、markerではなくtagの位置から意味を推測していました。最初のe tagをroot、最後をreply、中間をmentionとして扱っていたのです。この方法は曖昧さを生むため、いまは非推奨です。markerなしのe tagを見かけたら、古いclient由来である可能性が高いです。現在の実装は常に明示的なmarkerを出すべきです。
ただし、古いthreadを正しく表示したいclientは、両方の形式を解析する必要があります。実際のNIP-10 interoperabilityは一部が移行問題です。producerはmarked tagを出すべきですが、readerは古いposition-based formにも寛容である必要があります。
Building Thread Views
threadを表示するには、まずroot eventを取得し、そのrootを参照するe tagを持つeventをすべて問い合わせます。
["REQ", "thread", {"kinds": [1], "#e": ["<root-event-id>"]}]
結果をcreated_atで並べ、reply markerを使ってtree structureを構築します。replyがrootを指すeventはトップレベルのreplyです。replyが別のreplyを指すeventは入れ子のresponseになります。
主要ソース:
言及箇所:
関連項目: