NAME
Net::Nostr::Comment - NIP-22 comment threading
SYNOPSIS
use Net::Nostr::Comment;
# Comment on a nostr event (regular or addressable)
my $comment = Net::Nostr::Comment->comment(
event => $blog_post,
pubkey => $my_pubkey,
content => 'Great blog post!',
relay_url => 'wss://relay.example.com',
);
# Comment on an external identifier (URL, podcast, etc.)
my $comment = Net::Nostr::Comment->comment(
identifier => 'https://abc.com/articles/1',
kind => 'web',
pubkey => $my_pubkey,
content => 'Nice article!',
);
# Reply to an existing comment
my $reply = Net::Nostr::Comment->reply(
to => $parent_comment,
pubkey => $my_pubkey,
content => 'I agree!',
relay_url => 'wss://relay.example.com',
);
# Parse comment structure from an event
my $info = Net::Nostr::Comment->from_event($event);
if ($info) {
say "Root kind: " . $info->root_kind;
say "Parent kind: " . $info->parent_kind;
}
# Validate a comment event
Net::Nostr::Comment->validate($event);
DESCRIPTION
Implements NIP-22 comment threading for kind 1111 events. Comments are plaintext threading notes scoped to a root event or external identifier.
Comments use uppercase tags (E, A, I, K, P) for the root scope and lowercase tags (e, a, i, k, p) for the parent item. For top-level comments, root and parent point to the same target.
Comments MUST NOT be used to reply to kind 1 notes; use Net::Nostr::Thread (NIP-10) instead.
CONSTRUCTOR
new
my $info = Net::Nostr::Comment->new(%fields);
Creates a new Net::Nostr::Comment object. Typically returned by "from_event"; calling new directly is useful for testing or manual construction.
my $info = Net::Nostr::Comment->new(
root_tag_name => 'E',
root_kind => '30023',
root_value => 'abc123',
root_pubkey => $hex_pubkey,
);
Accepted fields: root_tag_name, root_value, root_relay, root_kind, root_pubkey, parent_tag_name, parent_value, parent_relay, parent_kind, parent_pubkey. Croaks on unknown arguments.
CLASS METHODS
comment
my $event = Net::Nostr::Comment->comment(
event => $target_event, # nostr event to comment on
pubkey => $hex_pubkey,
content => 'comment text',
relay_url => 'wss://relay.com/', # optional, defaults to ''
quotes => [{id => $eid, relay_url => $r, pubkey => $pk}], # optional
mentions => [$pubkey1], # optional
created_at => time(), # optional, passed to Event
);
my $event = Net::Nostr::Comment->comment(
identifier => 'https://example.com/article',
kind => 'web',
pubkey => $hex_pubkey,
content => 'comment text',
hint => 'https://...', # optional hint for I/i tags
);
Creates a kind 1111 comment event. Pass event for nostr events or identifier and kind for external identifiers (URLs, podcasts, etc.).
For addressable events (kinds 30000-39999), generates A/a tags with the event coordinate and an additional e tag referencing the event ID. For regular events, generates E/e tags. Tags K/k are always included with the target kind, and P/p tags include the author pubkey for nostr events.
Croaks if the target is a kind 1 event (use Net::Nostr::Thread instead).
# Comment on a NIP-94 file event
my $comment = Net::Nostr::Comment->comment(
event => $file_event,
pubkey => $my_pk,
content => 'Great file!',
);
# Comment on a podcast episode
my $comment = Net::Nostr::Comment->comment(
identifier => 'podcast:item:guid:d98d189b-...',
kind => 'podcast:item:guid',
pubkey => $my_pk,
content => 'Great episode!',
hint => 'https://fountain.fm/episode/...',
);
reply
my $event = Net::Nostr::Comment->reply(
to => $parent_comment,
pubkey => $hex_pubkey,
content => 'reply text',
relay_url => 'wss://relay.com/', # optional
quotes => [...], # optional
mentions => [...], # optional
);
Creates a kind 1111 reply to an existing comment. The root scope tags (E/A/I, K, P) are preserved from the parent comment's uppercase tags. The parent tags point to the comment being replied to with k set to 1111.
my $reply = Net::Nostr::Comment->reply(
to => $comment_event,
pubkey => $my_pk,
content => 'I agree!',
);
from_event
my $info = Net::Nostr::Comment->from_event($event);
Parses comment structure from a kind 1111 event. Returns a Net::Nostr::Comment object with accessors for root and parent scope, or undef if the event is not kind 1111.
my $info = Net::Nostr::Comment->from_event($event);
say $info->root_kind; # '30023'
say $info->parent_kind; # '1111' (if replying to a comment)
say $info->root_pubkey; # root event author, or undef
validate
Net::Nostr::Comment->validate($event);
Validates that an event is a well-formed NIP-22 comment. Croaks if:
Kind is not 1111
Missing root scope tag (
E,A, orI)Missing parent scope tag (
e,a, ori)Missing
Ktag (root kind)Missing
ktag (parent kind)
eval { Net::Nostr::Comment->validate($event) };
warn "Invalid comment: $@" if $@;
ACCESSORS
These are available on objects returned by "from_event".
root_tag_name
my $name = $info->root_tag_name; # 'E', 'A', or 'I'
The tag name used for the root scope.
root_value
my $val = $info->root_value;
The root scope value (event ID, event coordinate, or external identifier).
root_relay
my $relay = $info->root_relay;
Relay or web page hint for the root scope, or empty string.
root_kind
my $kind = $info->root_kind; # '30023', '1063', 'web', etc.
The K tag value identifying the root item kind.
root_pubkey
my $pk = $info->root_pubkey; # or undef for external identifiers
The P tag pubkey of the root event author, or undef if not available (e.g. for external identifiers).
parent_tag_name
my $name = $info->parent_tag_name; # 'e', 'a', or 'i'
The tag name used for the parent item.
parent_value
my $val = $info->parent_value;
The parent item value.
parent_relay
my $relay = $info->parent_relay;
Relay hint for the parent item, or empty string.
parent_kind
my $kind = $info->parent_kind; # '1111' for replies to comments
The k tag value identifying the parent item kind.
parent_pubkey
my $pk = $info->parent_pubkey;
The p tag pubkey of the parent item author, or undef.