NAME

Net::Nostr::Reaction - NIP-25 reactions

SYNOPSIS

use Net::Nostr::Reaction;

# Like a note (default content is +)
my $reaction = Net::Nostr::Reaction->react(
    event     => $note,
    pubkey    => $my_pubkey,
    relay_url => 'wss://relay.example.com',
);

# Dislike
my $reaction = Net::Nostr::Reaction->react(
    event     => $note,
    pubkey    => $my_pubkey,
    relay_url => 'wss://relay.example.com',
    content   => '-',
);

# Emoji reaction
my $reaction = Net::Nostr::Reaction->react(
    event     => $note,
    pubkey    => $my_pubkey,
    relay_url => 'wss://relay.example.com',
    content   => "\x{1F44D}",
);

# Custom emoji reaction (NIP-30)
my $reaction = Net::Nostr::Reaction->react(
    event     => $note,
    pubkey    => $my_pubkey,
    relay_url => 'wss://relay.example.com',
    content   => ':soapbox:',
    emoji     => ['soapbox', 'https://gleasonator.com/emoji/Gleasonator/soapbox.png'],
);

# React to external content (kind 17)
my $reaction = Net::Nostr::Reaction->react_external(
    pubkey  => $my_pubkey,
    content => "\x{2B50}",
    tags    => [
        ['k', 'web'],
        ['i', 'https://example.com'],
    ],
);

# Parse reaction from an event
my $info = Net::Nostr::Reaction->from_event($event);
if ($info) {
    say $info->is_like ? "Liked" : $info->content;
}

# Validate a reaction event
Net::Nostr::Reaction->validate($event);

DESCRIPTION

Implements NIP-25 reactions. A reaction is a kind 7 event used to react to other nostr events. The content field indicates the reaction value: + or empty string for a "like", - for a "dislike", or an emoji (including NIP-30 custom emoji) for an emoji reaction. Emoji reactions SHOULD NOT be interpreted as likes or dislikes.

Tags include an e tag with the reacted event's ID (MUST), a p tag with the author's pubkey (SHOULD), a k tag with the stringified kind (MAY), and for addressable events an a tag with the event coordinate (SHOULD). The e and a tags SHOULD include relay and pubkey hints. The p tag SHOULD include a relay hint. If multiple e or p tags are present, the target event's ID and pubkey should be last.

External content reactions (websites, podcasts, etc.) use kind 17 with NIP-73 k and i tags instead of e tags.

CONSTRUCTOR

new

my $info = Net::Nostr::Reaction->new(%fields);

Creates a new Net::Nostr::Reaction object. Typically returned by "from_event"; calling new directly is useful for testing or manual construction.

my $info = Net::Nostr::Reaction->new(
    event_id => 'aa' x 32,
    content  => '+',
);

Accepted fields: event_id, relay_url, author_pubkey, content, reacted_kind, event_coordinate. Croaks on unknown arguments.

CLASS METHODS

react

my $event = Net::Nostr::Reaction->react(
    event      => $original_event,    # Net::Nostr::Event to react to
    pubkey     => $hex_pubkey,        # reactor's hex pubkey
    relay_url  => 'wss://relay.example.com',
    content    => '+',                # optional, default '+'
    emoji      => ['name', 'url'],    # optional, NIP-30 custom emoji
    created_at => time(),             # optional, passed to Event
);

Creates a kind 7 reaction Net::Nostr::Event. The event parameter is the Net::Nostr::Event being reacted to. The pubkey is the reactor's hex public key.

The content defaults to + (like). Pass - for dislike, an emoji for emoji reaction, or a :shortcode: with the emoji parameter for a NIP-30 custom emoji reaction.

Returns a Net::Nostr::Event with kind 7 and the appropriate tags.

Croaks if event, pubkey, or relay_url is missing.

react_external

my $event = Net::Nostr::Reaction->react_external(
    pubkey  => $hex_pubkey,
    content => "\x{2B50}",
    tags    => [
        ['k', 'web'],
        ['i', 'https://example.com'],
    ],
);

Creates a kind 17 external content reaction Net::Nostr::Event. The tags must include NIP-73 k and i tags to reference the external content.

Returns a Net::Nostr::Event with kind 17.

Croaks if pubkey, content, or tags is missing.

from_event

my $info = Net::Nostr::Reaction->from_event($event);

Parses reaction structure from a kind 7 or kind 17 Net::Nostr::Event. Returns a Net::Nostr::Reaction object with accessors, or undef if the event is not a reaction kind.

my $info = Net::Nostr::Reaction->from_event($event);
say $info->is_like ? "Liked" : $info->content;

validate

Net::Nostr::Reaction->validate($event);

Validates that a Net::Nostr::Event is a well-formed NIP-25 reaction. Croaks if:

  • Kind is not 7 or 17

  • Kind 7 missing e tag

  • Kind 17 missing k or i tags

eval { Net::Nostr::Reaction->validate($event) };
warn "Invalid reaction: $@" if $@;

INSTANCE METHODS

is_like

$info->is_like;  # true for '+' or ''

Returns true if the reaction content is + or an empty string.

is_dislike

$info->is_dislike;  # true for '-'

Returns true if the reaction content is -.

ACCESSORS

These are available on objects returned by "from_event".

event_id

my $id = $info->event_id;

The ID of the reacted event (from the e tag), or undef for kind 17.

relay_url

my $url = $info->relay_url;

The relay URL hint (from the e tag), or undef.

author_pubkey

my $pk = $info->author_pubkey;

The pubkey of the reacted event's author (from the e or p tag), or undef.

content

my $c = $info->content;  # '+', '-', emoji, or ':shortcode:'

The reaction content.

reacted_kind

my $kind = $info->reacted_kind;  # '1' or 'web'

The stringified kind of the reacted event (from the k tag), or undef.

event_coordinate

my $coord = $info->event_coordinate;  # '30023:pubkey:d-tag'

The event coordinate (from the a tag), or undef. Only present when reacting to addressable events.

SEE ALSO

NIP-25, Net::Nostr, Net::Nostr::Event