NAME

Net::Nostr::RelayMonitor - NIP-66 Relay Discovery and Liveness Monitoring

SYNOPSIS

use Net::Nostr::RelayMonitor;

# Build a relay discovery event (kind 30166)
my $event = Net::Nostr::RelayMonitor->discovery_event(
    pubkey       => $pubkey,
    relay_url    => 'wss://relay.example.com/',
    network      => 'clearnet',
    nips         => [1, 11, 42],
    rtt_open     => '150',
    requirements => ['!payment', 'auth'],
);

# Build a monitor announcement event (kind 10166)
my $event = Net::Nostr::RelayMonitor->announcement_event(
    pubkey    => $pubkey,
    frequency => '3600',
    checks    => [qw(ws nip11 ssl dns)],
    timeouts  => [{ test => 'open', ms => '5000' }],
);

# Parse either kind
my $mon = Net::Nostr::RelayMonitor->from_event($event);
say $mon->relay_url;    # discovery events
say $mon->frequency;    # announcement events

# Validate
Net::Nostr::RelayMonitor->validate($event);

DESCRIPTION

Implements NIP-66 (Relay Discovery and Liveness Monitoring). Provides methods to build and parse two event types:

Kind 30166 -- Relay Discovery Events

Addressable events published by monitors documenting relay characteristics inferred from NIP-11 documents or probing. The d tag MUST be set to the relay's normalized URL (or a hex pubkey for non-URL relays). The content MAY include the stringified JSON of the relay's NIP-11 document.

Kind 10166 -- Relay Monitor Announcements

Replaceable events advertising a monitor's intent to publish discovery events at a regular frequency.

Clients MUST NOT require 30166 events to function. Clients SHOULD NOT trust a single monitor source.

CONSTRUCTOR

new

my $mon = Net::Nostr::RelayMonitor->new(%fields);

Creates a new Net::Nostr::RelayMonitor object. All fields are optional. Array fields (nips, requirements, topics, kinds, languages, timeouts, checks) default to []. Croaks on unknown arguments. Typically returned by "from_event".

CLASS METHODS

discovery_event

my $event = Net::Nostr::RelayMonitor->discovery_event(
    pubkey       => $hex_pubkey,
    relay_url    => 'wss://relay.example.com/',
    network      => 'clearnet',
    relay_type   => 'PrivateInbox',
    nips         => [1, 11, 42],
    requirements => ['!payment', 'auth'],
    topics       => ['nsfw'],
    kinds        => ['1', '!20000'],
    geohash      => 'ww8p1r4t8',
    languages    => ['en'],
    rtt_open     => '234',
    rtt_read     => '150',
    rtt_write    => '300',
    nip11        => '{"name":"My Relay"}',
    created_at   => time(),
);

Creates a kind 30166 addressable Net::Nostr::Event. relay_url is required and becomes the d tag. nip11, if provided, becomes the event content (otherwise empty string). Multi-value tags (nips, requirements, topics, kinds, languages) are emitted as repeated tags per the spec. Any remaining arguments are passed through to "new" in Net::Nostr::Event.

announcement_event

my $event = Net::Nostr::RelayMonitor->announcement_event(
    pubkey    => $hex_pubkey,
    frequency => '3600',
    timeouts  => [
        { test => 'open', ms => '5000' },
        { test => 'read', ms => '3000' },
        { ms => '10000' },                  # applies to all tests
    ],
    checks    => [qw(ws nip11 ssl dns geo)],
    geohash   => 'ww8p1r4t8',
    created_at => time(),
);

Creates a kind 10166 replaceable Net::Nostr::Event. frequency is required (seconds between publications). timeouts is an arrayref of hashrefs with ms (milliseconds) and optional test (test type). When test is omitted, the timeout applies to all tests. checks is an arrayref of lowercase check names. Any remaining arguments are passed through to "new" in Net::Nostr::Event.

from_event

my $mon = Net::Nostr::RelayMonitor->from_event($event);

Parses a kind 30166 or 10166 event into a Net::Nostr::RelayMonitor object. Returns undef if the event kind is neither 30166 nor 10166.

my $mon = Net::Nostr::RelayMonitor->from_event($event);
if ($event->kind == 30166) {
    say $mon->relay_url;
    say $mon->network;
} else {
    say $mon->frequency;
    say join ', ', @{$mon->checks};
}

validate

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

Validates a NIP-66 event. For kind 30166, checks that a d tag is present. For kind 10166, checks that a frequency tag is present. Croaks if the kind is unsupported or required tags are missing. Returns 1 on success.

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

ACCESSORS

Discovery Event Fields (kind 30166)

relay_url

Relay URL from the d tag. For non-URL relays, may be a hex pubkey.

network

Network type. SHOULD be one of clearnet, tor, i2p, loki.

relay_type

Relay type in PascalCase (e.g. PrivateInbox).

nips

Arrayref of supported NIP numbers (as strings).

requirements

Arrayref of requirement strings. False values use ! prefix (e.g. !payment). Corresponds to NIP-11 limitations.

topics

Arrayref of topic strings.

kinds

Arrayref of accepted/unaccepted kind strings. Unaccepted kinds use ! prefix (e.g. !20000).

geohash

NIP-52 geohash string. Used by both discovery and announcement events.

languages

Arrayref of ISO-639-1 language codes.

rtt_open

Open round-trip time in milliseconds (string).

rtt_read

Read round-trip time in milliseconds (string).

rtt_write

Write round-trip time in milliseconds (string).

nip11

Stringified JSON of the relay's NIP-11 informational document, or undef.

Announcement Event Fields (kind 10166)

frequency

Publication frequency in seconds (string).

timeouts

Arrayref of timeout hashrefs. Each has ms (milliseconds) and optional test (test type). When test is absent, the timeout applies to all tests.

# With test type
{ test => 'open', ms => '5000' }

# Without test type (applies to all)
{ ms => '5000' }

checks

Arrayref of lowercase check name strings (e.g. ws, nip11, ssl, dns, geo).

SEE ALSO

NIP-66, Net::Nostr::RelayInfo, Net::Nostr, Net::Nostr::Event