Net-Nostr
view release on metacpan or search on metacpan
lib/Net/Nostr/Calendar.pm view on Meta::CPAN
croak "RSVP MUST have a 'status' tag" unless exists $has{status};
croak "RSVP status MUST be accepted, declined, or tentative"
unless $has{status} =~ /\A(?:accepted|declined|tentative)\z/;
}
return 1;
}
1;
__END__
=head1 NAME
Net::Nostr::Calendar - NIP-52 Calendar Events
=head1 SYNOPSIS
use Net::Nostr::Calendar;
# Date-based calendar event (kind 31922)
my $event = Net::Nostr::Calendar->date_event(
pubkey => $hex_pubkey,
identifier => 'vacation-2024',
title => 'Summer Vacation',
content => 'Two weeks off',
start => '2024-07-01',
end => '2024-07-15',
locations => ['Beach Resort'],
participants => [[$friend_pk, 'wss://relay', 'attendee']],
);
# Time-based calendar event (kind 31923)
my $event = Net::Nostr::Calendar->time_event(
pubkey => $hex_pubkey,
identifier => 'standup',
title => 'Daily Standup',
start => 1700000000,
end => 1700003600,
start_tzid => 'America/New_York',
days => [19675],
);
# Calendar (kind 31924)
my $cal = Net::Nostr::Calendar->calendar(
pubkey => $hex_pubkey,
identifier => 'personal',
title => 'Personal Calendar',
events => [
["31922:$pk:vacation-2024", 'wss://relay'],
],
);
# RSVP (kind 31925)
my $rsvp = Net::Nostr::Calendar->rsvp(
pubkey => $hex_pubkey,
identifier => 'rsvp-1',
event_coord => "31922:$organizer_pk:vacation-2024",
status => 'accepted',
fb => 'busy',
);
# Parse any calendar event
my $parsed = Net::Nostr::Calendar->from_event($event);
# Validate
Net::Nostr::Calendar->validate($event);
=head1 DESCRIPTION
Implements NIP-52 (Calendar Events). Four addressable event kinds are
used:
=over 4
=item * B<Date-Based Calendar Event> (kind 31922) - All-day or multi-day
events where time and time zone hold no significance.
=item * B<Time-Based Calendar Event> (kind 31923) - Events spanning
between a start time and end time.
=item * B<Calendar> (kind 31924) - A collection of calendar events.
=item * B<Calendar Event RSVP> (kind 31925) - Attendance response to a
calendar event.
=back
All four kinds are addressable and deletable per NIP-09.
=head2 Common tags for calendar events
Both date-based and time-based calendar events share these tags:
=over 4
=item * C<d> (required) - unique identifier
=item * C<title> (required) - title of the event
=item * C<summary> (optional) - brief description
=item * C<image> (optional) - URL of an image
=item * C<location> (optional, repeated) - location string
=item * C<g> (optional) - geohash for searchable location
=item * C<p> (optional, repeated) - participant pubkey, relay URL, and role
=item * C<t> (optional, repeated) - hashtag
=item * C<r> (optional, repeated) - reference URL
=item * C<a> (repeated) - reference to kind 31924 calendar
=back
The deprecated C<name> tag is mapped to C<title> when parsing if
C<title> is not present.
lib/Net/Nostr/Calendar.pm view on Meta::CPAN
C<start> date is inclusive and in ISO 8601 format (YYYY-MM-DD). The
C<end> date is exclusive. If C<end> is omitted, the event ends on the
same date as C<start>. C<start> must be less than C<end> if both are
present (enforced by L</validate>).
=head2 time_event
my $event = Net::Nostr::Calendar->time_event(
pubkey => $hex_pubkey, # required
identifier => $id, # required (d tag)
title => $title, # required (title tag)
start => $unix_timestamp, # required
end => $unix_timestamp, # optional
start_tzid => 'America/New_York', # optional (IANA TZ)
end_tzid => 'America/New_York', # optional (IANA TZ)
days => [$day_number], # required per spec (D tags)
content => $description, # optional, defaults to ''
summary => $text, # optional
image => $url, # optional
locations => [$location], # optional
geohash => $geohash, # optional
participants => [[$pk, $relay, $role]], # optional
hashtags => [$tag], # optional
references => [$url], # optional
calendars => [$coord], # optional (a tags)
created_at => time(), # optional
);
Creates a kind 31923 time-based calendar L<Net::Nostr::Event>. The
C<start> timestamp is inclusive (Unix seconds). The C<end> timestamp is
exclusive. If C<end> is omitted, the event ends instantaneously.
C<start> must be less than C<end> if both are present (enforced by
L</validate>). C<days> are day-granularity timestamps (C<D> tags)
calculated as C<floor(unix_seconds / 86400)>. The spec requires at
least one C<D> tag (enforced by L</validate>).
=head2 calendar
my $event = Net::Nostr::Calendar->calendar(
pubkey => $hex_pubkey, # required
identifier => $id, # required (d tag)
title => $title, # required (title tag)
content => $description, # optional, defaults to ''
events => [[$coord, $relay]], # optional (a tags)
);
Creates a kind 31924 calendar L<Net::Nostr::Event>. C<events> is an
arrayref of arrayrefs, each containing a calendar event coordinate and
optional relay URL.
=head2 rsvp
my $event = Net::Nostr::Calendar->rsvp(
pubkey => $hex_pubkey, # required
identifier => $id, # required (d tag)
event_coord => $coord, # required (a tag)
status => 'accepted', # required
event_relay => $url, # optional (a tag relay)
event_id => $eid, # optional (e tag)
event_id_relay => $url, # optional (e tag relay)
fb => 'busy', # optional (free/busy)
event_author => $pk, # optional (p tag)
event_author_relay => $url, # optional (p tag relay)
content => $note, # optional, defaults to ''
);
Creates a kind 31925 RSVP L<Net::Nostr::Event>. C<status> must be
C<accepted>, C<declined>, or C<tentative>. The C<fb> tag is
automatically omitted when C<status> is C<declined>.
=head2 from_event
my $cal = Net::Nostr::Calendar->from_event($event);
Parses a kind 31922, 31923, 31924, or 31925 event into a
C<Net::Nostr::Calendar> object. Returns C<undef> for unrecognized kinds.
Handles the deprecated C<name> tag (mapped to C<title> if C<title> is
absent).
=head2 validate
Net::Nostr::Calendar->validate($event);
Validates a NIP-52 event. Croaks if:
=over
=item * Kind is not 31922, 31923, 31924, or 31925
=item * Kind 31922/31923 missing C<d>, C<title>, or C<start> tag
=item * Kind 31922/31923 C<start> is not less than C<end> (when C<end>
is present)
=item * Kind 31923 missing C<D> tag
=item * Kind 31924 missing C<d> or C<title> tag
=item * Kind 31925 missing C<d>, C<a>, or C<status> tag
=item * Kind 31925 C<status> is not C<accepted>, C<declined>, or
C<tentative>
=back
Returns 1 on success.
=head1 ACCESSORS
=head2 identifier
The C<d> tag value.
=head2 title
The calendar event or calendar title.
=head2 description
The event content. Defaults to C<''>.
lib/Net/Nostr/Calendar.pm view on Meta::CPAN
Image URL, or C<undef>.
=head2 locations
Arrayref of location strings. Defaults to C<[]>.
=head2 geohash
Geohash string, or C<undef>.
=head2 participants
Arrayref of arrayrefs, each containing pubkey, optional relay URL, and
optional role. Defaults to C<[]>.
=head2 hashtags
Arrayref of hashtag strings. Defaults to C<[]>.
=head2 references
Arrayref of reference URL strings. Defaults to C<[]>.
=head2 calendars
Arrayref of kind 31924 calendar coordinates (from C<a> tags in calendar
events). Defaults to C<[]>.
=head2 calendar_events
Arrayref of arrayrefs, each containing a calendar event coordinate and
optional relay URL (from C<a> tags in calendars). Defaults to C<[]>.
=head2 start_tzid
IANA Time Zone Database identifier for the start time (kind 31923 only).
=head2 end_tzid
IANA Time Zone Database identifier for the end time (kind 31923 only).
=head2 days
Arrayref of day-granularity timestamp strings (C<D> tags, kind 31923
only). Defaults to C<[]>.
=head2 event_coord
The calendar event coordinate (C<a> tag value, RSVP only).
=head2 event_id
The specific calendar event revision ID (C<e> tag value, RSVP only).
=head2 status
RSVP status: C<accepted>, C<declined>, or C<tentative>.
=head2 fb
Free/busy indicator: C<free> or C<busy>. Must be omitted or ignored if
C<status> is C<declined>.
=head2 event_author
Pubkey of the calendar event author (RSVP only).
=head1 SEE ALSO
L<NIP-52|https://github.com/nostr-protocol/nips/blob/master/52.md>,
L<Net::Nostr>, L<Net::Nostr::Event>
=cut
( run in 1.840 second using v1.01-cache-2.11-cpan-98e64b0badf )