NAME

Net::Nostr::Thread - NIP-10 text note threading

SYNOPSIS

use Net::Nostr::Thread;

# Create a direct reply to a root post
my $reply = Net::Nostr::Thread->reply(
    to      => $root_event,
    pubkey  => $my_pubkey,
    content => 'Great post!',
);

# Create a reply to a reply
my $deep_reply = Net::Nostr::Thread->reply(
    to        => $reply_event,
    pubkey    => $my_pubkey,
    content   => 'I agree',
    relay_url => 'wss://relay.example.com/',
);

# Quote an event
my $quote = Net::Nostr::Thread->quote(
    event   => $original,
    pubkey  => $my_pubkey,
    content => 'Look at this nostr:nevent1...',
);

# Parse thread info from an event
my $thread = Net::Nostr::Thread->from_event($event);
if ($thread) {
    say "Root: " . $thread->root_id;
    say "Reply to: " . $thread->reply_id if $thread->reply_id;
}

# Check if an event is a reply
say "is reply" if Net::Nostr::Thread->is_reply($event);

DESCRIPTION

Implements NIP-10 text note threading for kind 1 events. Provides methods to create properly tagged reply and quote events, and to parse thread structure from existing events.

Uses marked e tags (preferred) with root and reply markers. Also parses deprecated positional e tags for backward compatibility.

CLASS METHODS

reply

my $event = Net::Nostr::Thread->reply(
    to         => $parent_event,
    pubkey     => $hex_pubkey,
    content    => 'reply text',
    relay_url  => 'wss://relay.com/',   # optional, defaults to ''
    created_at => time(),               # optional, passed to Event
);

Creates a kind 1 reply event with proper marked e tags and p tags. A direct reply to a root post gets a single e tag with marker root. A reply to a reply gets two e tags: root and reply, sorted by reply stack (root first).

The reply's p tags include the parent author and all of the parent's p tags, deduplicated, excluding the replier's own pubkey.

Croaks if the parent event is not kind 1 (use NIP-22 for other kinds).

# Direct reply to root
my $reply = Net::Nostr::Thread->reply(
    to => $root, pubkey => $pk, content => 'hello',
);
# tags: [['e', $root_id, '', 'root', $root_pubkey], ['p', $root_pubkey]]

# Reply to a reply
my $deep = Net::Nostr::Thread->reply(
    to => $mid_reply, pubkey => $pk, content => 'hi',
);
# tags: [['e', $root_id, '', 'root', ...], ['e', $mid_id, '', 'reply', ...], ...]

quote

my $event = Net::Nostr::Thread->quote(
    event     => $quoted_event,
    pubkey    => $hex_pubkey,
    content   => 'look at this nostr:nevent1...',
    relay_url => 'wss://relay.com/',   # optional
);

Creates a kind 1 event with a q tag referencing the quoted event. The quoted event's author is added as a p tag unless the quoter is the same pubkey (no self-reference).

my $qt = Net::Nostr::Thread->quote(
    event => $original, pubkey => $pk, content => 'wow',
);
# tags: [['q', $original_id, '', $original_pubkey], ['p', $original_pubkey]]

from_event

my $thread = Net::Nostr::Thread->from_event($event);

Parses thread structure from an event's e tags. Returns a Net::Nostr::Thread object, or undef if the event has no e tags.

Prefers marked e tags (with root/reply markers). Falls back to deprecated positional parsing for unmarked tags.

my $thread = Net::Nostr::Thread->from_event($event);
say $thread->root_id;
say $thread->reply_id if $thread->reply_id;

is_reply

my $bool = Net::Nostr::Thread->is_reply($event);

Returns true if the event has any e tags indicating it is a thread reply.

if (Net::Nostr::Thread->is_reply($event)) {
    my $thread = Net::Nostr::Thread->from_event($event);
    ...
}

ACCESSORS

root_id

my $id = $thread->root_id;

The event ID of the thread root.

root_relay

my $relay = $thread->root_relay;

Relay URL hint for the root event, or empty string.

root_pubkey

my $pk = $thread->root_pubkey;

Public key of the root event author, if available.

reply_id

my $id = $thread->reply_id;

The event ID of the direct parent, or undef for direct replies to root.

reply_relay

my $relay = $thread->reply_relay;

Relay URL hint for the parent event, or empty string.

reply_pubkey

my $pk = $thread->reply_pubkey;

Public key of the parent event author, if available.

mentions

my $ids = $thread->mentions;  # arrayref

Event IDs from deprecated positional e tags that are neither root nor reply (the "middle" tags). Empty arrayref for marked tags.

SEE ALSO

Net::Nostr, Net::Nostr::Event