NAME
Net::Nostr::Community - NIP-72 moderated communities
SYNOPSIS
use Net::Nostr::Community;
# Define a community
my $event = Net::Nostr::Community->community(
pubkey => $owner_pubkey,
identifier => 'my-community',
name => 'My Community',
description => 'A place for discussion',
image => ['https://example.com/banner.jpg', '1200x400'],
moderators => [
{ pubkey => $mod_pubkey, relay => 'wss://relay1' },
],
relays => [
{ url => 'wss://relay.example.com', marker => 'requests' },
],
);
# Post to a community (top-level, kind 1111)
my $post = Net::Nostr::Community->post(
pubkey => $user_pubkey,
content => 'Hello community!',
community_pubkey => $owner_pubkey,
community_d => 'my-community',
);
# Reply to a post (nested, kind 1111)
my $reply = Net::Nostr::Community->reply(
pubkey => $user_pubkey,
content => 'Great post!',
community_pubkey => $owner_pubkey,
community_d => 'my-community',
parent_id => $parent_event_id,
parent_pubkey => $parent_author,
parent_kind => '1111',
);
# Approve a post (moderator action, kind 4550)
my $approval = Net::Nostr::Community->approval(
pubkey => $mod_pubkey,
community_pubkey => $owner_pubkey,
community_d => 'my-community',
post => $post_event,
);
# Parse a community or approval event
my $info = Net::Nostr::Community->from_event($event);
say $info->name; # 'My Community'
DESCRIPTION
Implements NIP-72 moderated communities (Reddit-style). Communities are defined by kind 34550 addressable events that list moderators, relays, and metadata. Users post to communities using kind 1111 (NIP-22) events with community-scoped tags. Moderators approve posts with kind 4550 events.
The d tag of a community definition MAY double as its name, but if a name tag is provided, clients SHOULD display it instead.
Posts use uppercase tags (A, P, K) for root scope (the community) and lowercase tags (a/e, p, k) for the parent. For top-level posts, both sets point to the community itself.
CONSTRUCTOR
new
my $info = Net::Nostr::Community->new(%fields);
Creates a new Net::Nostr::Community object. Typically returned by "from_event"; calling new directly is useful for testing or manual construction.
my $info = Net::Nostr::Community->new(
identifier => 'my-community',
name => 'My Community',
description => 'A place for discussion.',
);
Accepted fields: identifier, name, description, image, moderators (defaults to []), relays (defaults to []), communities (defaults to []), post_id, post_coordinate, post_author, post_kind. Croaks on unknown arguments.
CLASS METHODS
community
my $event = Net::Nostr::Community->community(
pubkey => $hex_pubkey, # required
identifier => 'my-community', # required (d tag)
name => 'Display Name', # optional (SHOULD)
description => 'About this place', # optional
image => ['url', '800x600'], # optional (with optional dims)
moderators => [ # optional
{ pubkey => $pk, relay => 'wss://...' },
],
relays => [ # optional (MAY)
{ url => 'wss://...', marker => 'requests' },
],
extra_tags => [['rules', '...']], # optional
);
Creates a kind 34550 community definition Net::Nostr::Event.
Moderator entries become p tags with the moderator role. The relay field is optional per moderator. Relay entries become relay tags with an optional marker (author, requests, approvals).
post
my $event = Net::Nostr::Community->post(
pubkey => $hex_pubkey, # required
content => 'Hello!', # required
community_pubkey => $community_owner, # required
community_d => 'my-community', # required
relay => 'wss://...', # optional
);
Creates a kind 1111 top-level post to a community. Both uppercase and lowercase NIP-22 tags point to the community definition, as specified by the NIP.
reply
my $event = Net::Nostr::Community->reply(
pubkey => $hex_pubkey, # required
content => 'I agree!', # required
community_pubkey => $community_owner, # required
community_d => 'my-community', # required
parent_id => $event_id, # required
parent_pubkey => $parent_pk, # required
parent_kind => '1111', # required
relay => 'wss://...', # optional
);
Creates a kind 1111 nested reply. Uppercase tags point to the community definition (root scope), lowercase tags point to the parent post or reply.
approval
my $event = Net::Nostr::Community->approval(
pubkey => $mod_pubkey, # required
community_pubkey => $community_owner, # required (or use communities)
community_d => 'my-community', # required (or use communities)
post => $post_event, # required
relay => 'wss://...', # optional
approve_via => 'e', # optional: 'e', 'a', or 'both'
);
Creates a kind 4550 approval event. The content is the JSON-stringified post event. The approval MUST include a community a tag, a post reference (e or a tag), the post author's p tag, and a k tag with the post kind.
For replaceable events, approve_via controls how the post is referenced:
For approving a post across multiple communities:
my $event = Net::Nostr::Community->approval(
pubkey => $mod_pubkey,
communities => [
{ pubkey => $pk1, d => 'comm1', relay => 'wss://r1' },
{ pubkey => $pk2, d => 'comm2' },
],
post => $post_event,
);
from_event
my $info = Net::Nostr::Community->from_event($event);
Parses a kind 34550 or 4550 event. Returns a Net::Nostr::Community object with accessors, or undef if the event kind is not recognized.
For kind 34550 (community definition), the returned object has identifier, name, description, image, moderators, and relays accessors.
For kind 4550 (approval), the returned object has communities, post_id, post_coordinate, post_author, and post_kind accessors.
validate
Net::Nostr::Community->validate($event);
Validates that an event is a well-formed NIP-72 event. Croaks if:
Kind is not 34550 or 4550
Kind 34550 missing
dtagKind 4550 missing community
atag (34550:...)Kind 4550 missing
eoratag for the postKind 4550 missing
ptag for the post author
community_filter
my $filter = Net::Nostr::Community->community_filter(
identifiers => ['my-community'],
authors => [$owner_pk],
);
Returns a hashref filter for querying community definitions.
approval_filter
my $filter = Net::Nostr::Community->approval_filter(
community => '34550:pubkey:identifier',
authors => [$mod_pk],
);
Returns a hashref filter for querying approval events.
legacy_post_filter
my $filter = Net::Nostr::Community->legacy_post_filter(
community => '34550:pubkey:identifier',
);
Returns a hashref filter for querying legacy kind 1 posts tagged with a community. Clients MAY use this for backwards compatibility but SHOULD NOT create new kind 1 posts for communities.
ACCESSORS
These are available on objects returned by "from_event".
identifier
my $id = $info->identifier;
The d tag value (community definition).
name
my $name = $info->name; # or undef
The name tag value, or undef. When undef, the identifier MAY be used as a display name.
description
my $desc = $info->description; # or undef
The community description, or undef.
image
my $img = $info->image; # ['url', '800x600'] or ['url'] or undef
Arrayref of the image URL and optional dimensions, or undef.
moderators
my $mods = $info->moderators;
# [{ pubkey => '...', relay => '...' }, ...]
Arrayref of hashrefs, each with pubkey and optional relay.
relays
my $relays = $info->relays;
# [{ url => 'wss://...', marker => 'requests' }, ...]
Arrayref of hashrefs, each with url and optional marker.
communities
my $comms = $info->communities; # ['34550:pk:id', ...]
Arrayref of community coordinates (from approval events).
post_id
my $id = $info->post_id; # or undef
The approved post's event ID (from e tag), or undef.
post_coordinate
my $coord = $info->post_coordinate; # or undef
The approved post's event coordinate (from non-community a tag), or undef.
post_author
my $pk = $info->post_author;
The approved post author's pubkey (from p tag).
post_kind
my $kind = $info->post_kind; # '1111'
The approved post's kind (from k tag).