NAME

Net::Nostr::RelayInfo - NIP-11 relay information document

SYNOPSIS

use Net::Nostr::RelayInfo;

# Build a relay information document
my $info = Net::Nostr::RelayInfo->new(
    name           => 'My Relay',
    description    => 'A relay for everyone',
    pubkey         => $admin_pubkey,
    self           => $relay_pubkey,
    contact        => 'mailto:admin@example.com',
    supported_nips => [1, 9, 11, 42, 44],
    software       => 'https://example.com/relay',
    version        => '1.0.0',
);

# Serialize to JSON
my $json = $info->to_json;

# Parse a relay info document (e.g. from an HTTP response)
my $info = Net::Nostr::RelayInfo->from_json($json);
say $info->name;
say join(', ', @{$info->supported_nips});

# Generate an HTTP response with CORS headers
my $http_response = $info->to_http_response;

# Set on a relay to enable NIP-11
use Net::Nostr::Relay;
my $relay = Net::Nostr::Relay->new(
    relay_info => $info,
);
$relay->start('127.0.0.1', 8080);

DESCRIPTION

Implements NIP-11, the relay information document. This is a JSON document served over HTTP at the same URI as the relay's WebSocket endpoint. Clients request it with an Accept: application/nostr+json header.

When a relay_info is set on a Net::Nostr::Relay, the relay will automatically serve the document in response to HTTP requests with the correct Accept header, and handle CORS preflight OPTIONS requests.

CONSTRUCTOR

new

my $info = Net::Nostr::RelayInfo->new(
    name             => 'My Relay',
    description      => 'A relay for everyone',
    banner           => 'https://example.com/banner.jpg',
    icon             => 'https://example.com/icon.png',
    pubkey           => $admin_pubkey_hex,
    self             => $relay_pubkey_hex,
    contact          => 'mailto:admin@example.com',
    supported_nips   => [1, 9, 11],
    software         => 'https://example.com/relay',
    version          => '1.0.0',
    terms_of_service => 'https://example.com/tos',
    limitation       => { max_subscriptions => 50 },
    payments_url     => 'https://example.com/pay',
    fees             => { admission => [{ amount => 1000, unit => 'msats' }] },
);

All fields are optional and may be omitted. Any unrecognized keys are stored as extension fields and included in to_json output. See "extensions". The name field SHOULD be less than 30 characters. The pubkey field is the administrative contact pubkey. The self field is the relay's own pubkey. supported_nips is an arrayref of integer NIP numbers.

The limitation hashref may contain any of the following keys:

my $info = Net::Nostr::RelayInfo->new(
    limitation => {
        max_message_length   => 16384,
        max_subscriptions    => 300,
        max_limit            => 5000,
        max_subid_length     => 100,
        max_event_tags       => 100,
        max_content_length   => 8196,
        min_pow_difficulty   => 30,
        auth_required        => \1,
        payment_required     => \1,
        restricted_writes    => \1,
        created_at_lower_limit => 31536000,
        created_at_upper_limit => 3,
        default_limit        => 500,
    },
);

The fees hashref maps fee types to arrayrefs of fee entries. Each fee entry has amount and unit keys, and optionally period (for subscriptions) or kinds (for per-kind publication fees):

my $info = Net::Nostr::RelayInfo->new(
    payments_url => 'https://my-relay/payments',
    fees => {
        admission    => [{ amount => 1000000, unit => 'msats' }],
        subscription => [{ amount => 5000000, unit => 'msats',
                           period => 2592000 }],
        publication  => [{ kinds => [4], amount => 100,
                           unit => 'msats' }],
    },
);

CLASS METHODS

from_json

my $info = Net::Nostr::RelayInfo->from_json($json_string);

Parses a JSON relay information document. Unknown fields are preserved as extension fields and are available via "extensions".

use HTTP::Tiny;
my $resp = HTTP::Tiny->new->get($relay_url, {
    headers => { Accept => 'application/nostr+json' },
});
die "Failed to fetch relay info: $resp->{status}"
    unless $resp->{success};
my $info = Net::Nostr::RelayInfo->from_json($resp->{content});

cors_preflight_response

my $http = Net::Nostr::RelayInfo->cors_preflight_response;

Returns an HTTP 204 response string with CORS headers for handling OPTIONS preflight requests. May be called as a class method or a function -- the invocant is not used.

METHODS

to_json

my $json = $info->to_json;

Serializes the relay information document to a JSON string. Only fields that have been set are included.

to_http_response

my $http = $info->to_http_response;

Returns a complete HTTP 200 response string with the JSON body, Content-Type: application/nostr+json, and the required CORS headers (Access-Control-Allow-Origin, Access-Control-Allow-Headers, Access-Control-Allow-Methods).

ACCESSORS

name

Relay name (SHOULD be less than 30 characters).

description

Relay description.

Banner image URL.

icon

Icon image URL.

pubkey

Admin contact pubkey (64-char lowercase hex).

self

Relay's own pubkey (64-char lowercase hex).

contact

Admin contact URI (e.g. mailto:admin@example.com).

supported_nips

Arrayref of supported NIP numbers.

software

URL of the relay software project.

version

Relay software version string.

terms_of_service

URL of terms of service.

limitation

Hashref of relay limitations (see "new" for supported keys).

payments_url

URL for relay payment information.

fees

Hashref of fee schedules (see "new" for structure).

extensions

my $ext = $info->extensions;  # hashref or empty hashref

Returns a shallow copy of any extension fields passed to the constructor that are not part of the NIP-11 standard fields. These are included in the JSON output of to_json and to_http_response.

my $info = Net::Nostr::RelayInfo->new(
    name    => 'Overnet Relay',
    overnet => { version => '1.0', features => ['chat'] },
);
my $ext = $info->extensions;
# { overnet => { version => '1.0', features => ['chat'] } }

SEE ALSO

NIP-11, Net::Nostr, Net::Nostr::Relay