NAME

Net::Nostr::Mention - NIP-27 text note references

SYNOPSIS

use Net::Nostr::Mention qw(
    extract_mentions replace_mentions
    mention_pubkey mention_event mention_addr
);

my $pk = '7e7e9c42a91bfef19fa929e5fda1b72e0ebc1a4c1141673e2794234d86addf4e';
my $id = 'aaf9dd42b3de2a1a2f95e50fdbbef66e1afb165152a581a3ee75ac39a0559cd2';

# Create mentions for use in event content
my $m1 = mention_pubkey($pk);
# nostr:npub1...

my $m2 = mention_pubkey($pk, relays => ['wss://relay.com']);
# nostr:nprofile1...

my $m3 = mention_event($id);
# nostr:note1...

my $m4 = mention_event($id, author => $pk, kind => 1);
# nostr:nevent1...

my $m5 = mention_addr(
    identifier => 'my-article', pubkey => $pk, kind => 30023,
);
# nostr:naddr1...

# Extract all mentions from content
my $content = "hello $m1 see also $m3";
my @mentions = extract_mentions($content);
# @mentions = ({ type => 'npub', data => $pk, uri => 'nostr:npub1...', ... },
#              { type => 'note', data => $id, uri => 'nostr:note1...', ... })

# Replace mentions with display text
my $display = replace_mentions($content, sub {
    my ($mention) = @_;
    return '@someone' if $mention->{type} eq 'npub';
    return '[event]'  if $mention->{type} eq 'note';
    return $mention->{uri};  # keep as-is
});
# 'hello @someone see also [event]'

DESCRIPTION

Implements NIP-27 text note references. This NIP standardizes inline references to other events and profiles within event content using nostr: URIs (NIP-21) containing NIP-19 bech32-encoded entities.

When creating events, use "mention_pubkey", "mention_event", and "mention_addr" to produce properly formatted nostr: URIs to embed in content.

When displaying events, use "extract_mentions" to find all references in content, and "replace_mentions" to substitute them with display text such as profile names or event previews.

Including p, e, or q tags for mentioned entities is optional per NIP-27. Clients should add tags when they want the mentioned profile to be notified or the referenced event to recognize the mention as a reply.

FUNCTIONS

All functions are exportable. None are exported by default.

extract_mentions

my @mentions = extract_mentions($content);

Finds all nostr: URIs in the given content string. Returns a list of hashrefs, one per mention, in order of appearance. Each hashref contains:

type - entity type: npub, note, nprofile, nevent, or naddr
data - decoded data: hex string for bare types (npub, note), hashref for TLV types (nprofile, nevent, naddr)
uri - the full nostr:... string as it appeared in content
start - byte offset of the start of the URI in content
end - byte offset of the end of the URI in content

nsec URIs are silently skipped (they must not appear in nostr: URIs per NIP-21). Invalid bech32 strings are silently skipped.

use Net::Nostr::Bech32 qw(encode_npub);
my $npub = encode_npub('aa' x 32);
my $content = "hello nostr:$npub world";
my @m = extract_mentions($content);
say $m[0]{type};   # 'npub'
say $m[0]{start};  # 6
say substr($content, $m[0]{start}, $m[0]{end} - $m[0]{start});
# nostr:npub1...
say $m[0]{data};   # 'aa' x 32

replace_mentions

my $display = replace_mentions($content, \&callback);

Replaces each nostr: mention in content with the return value of the callback. The callback receives a mention hashref (same structure as "extract_mentions") and should return a replacement string.

use Net::Nostr::Bech32 qw(encode_npub encode_note);
my $npub = encode_npub('aa' x 32);
my $note = encode_note('bb' x 32);
my $content = "by nostr:$npub see nostr:$note";
my $display = replace_mentions($content, sub {
    my ($m) = @_;
    return '@' . substr($m->{data}, 0, 8) . '...' if $m->{type} eq 'npub';
    return '[event]' if $m->{type} eq 'note' || $m->{type} eq 'nevent';
    return $m->{uri};
});
# 'by @aaaaaaaa... see [event]'

mention_pubkey

my $uri = mention_pubkey($hex_pubkey);
my $uri = mention_pubkey($hex_pubkey, relays => ['wss://relay.com']);

Creates a nostr: URI for a public key. Returns nostr:npub1... when no options are given, or nostr:nprofile1... when relay hints are provided.

my $pk = 'aa' x 32;
my $content = "hello " . mention_pubkey($pk) . " how are you?";
# 'hello nostr:npub1... how are you?'

mention_event

my $uri = mention_event($hex_event_id);
my $uri = mention_event($hex_event_id, relays => \@r, author => $pk, kind => $k);

Creates a nostr: URI for an event. Returns nostr:note1... when no options are given, or nostr:nevent1... when any of relays, author, or kind are provided.

my $pk = 'aa' x 32;
my $id = 'bb' x 32;
my $content = "see " . mention_event($id, author => $pk, kind => 1);
# 'see nostr:nevent1...'

mention_addr

my $uri = mention_addr(
    identifier => $d_tag,
    pubkey     => $hex_pubkey,
    kind       => $kind,
    relays     => \@relays,   # optional
);

Creates a nostr:naddr1... URI for an addressable event. identifier, pubkey, and kind are required. relays is optional.

my $pk = 'aa' x 32;
my $content = "read " . mention_addr(
    identifier => 'my-article', pubkey => $pk, kind => 30023,
);
# 'read nostr:naddr1...'

SEE ALSO

NIP-27, NIP-21, Net::Nostr, Net::Nostr::Bech32