NAME

Net::Nostr::AppHandler - NIP-89 recommended application handlers

SYNOPSIS

use Net::Nostr::AppHandler;

my $pubkey = 'aa' x 32;
my $app_pk = 'bb' x 32;

# Recommend an app for handling kind 31337 events
my $event = Net::Nostr::AppHandler->recommendation(
    pubkey     => $pubkey,
    event_kind => '31337',
    apps       => [
        {
            coordinate => "31990:$app_pk:zapstr",
            relay      => 'wss://relay.example.com',
            platform   => 'web',
        },
    ],
);

# Publish handler information for an app
my $handler = Net::Nostr::AppHandler->handler(
    pubkey     => $app_pk,
    identifier => 'zapstr',
    kinds      => ['31337'],
    content    => '{"name":"Zapstr","picture":"https://example.com/icon.png"}',
    platforms  => [
        { platform => 'web', url => 'https://zapstr.live/a/<bech32>', entity => 'nevent' },
        { platform => 'web', url => 'https://zapstr.live/p/<bech32>', entity => 'nprofile' },
        { platform => 'ios', url => 'com.zapstr:///<bech32>' },
    ],
);

# Add a client tag to any event (MAY)
my $tag = Net::Nostr::AppHandler->client_tag(
    name       => 'My Client',
    coordinate => "31990:$app_pk:my-client",
    relay      => 'wss://relay1',
);

# Parse a recommendation or handler event
my $info = Net::Nostr::AppHandler->from_event($event);
say $info->event_kind;  # '31337'

# Query filters for discovery
my $filter = Net::Nostr::AppHandler->recommendation_filter(
    event_kind => '31337',
    authors    => [$pubkey],
);

DESCRIPTION

Implements NIP-89 recommended application handlers. This NIP provides a way to discover applications that can handle unknown event kinds through two event types:

Recommendations (kind 31989)

Addressable events where a user recommends one or more applications for handling a specific event kind. The d tag contains the supported event kind, and a tags reference handler information events.

Handler information (kind 31990)

Addressable events published by applications describing how to redirect users. Contains k tags for supported event kinds and platform-specific URL templates with <bech32> placeholders that clients replace with NIP-19-encoded entities.

CONSTRUCTOR

new

my $info = Net::Nostr::AppHandler->new(%fields);

Creates a new Net::Nostr::AppHandler object. Typically returned by "from_event"; calling new directly is useful for testing or manual construction.

my $info = Net::Nostr::AppHandler->new(
    event_kind => '31337',
    apps       => [],
    kinds      => [1, 30023],
);

Accepted fields: event_kind, identifier, kinds (defaults to []), content (defaults to ''), apps (defaults to []), platforms (defaults to []). Croaks on unknown arguments.

CLASS METHODS

recommendation

my $event = Net::Nostr::AppHandler->recommendation(
    pubkey     => $hex_pubkey,           # required
    event_kind => '31337',               # required (d tag value)
    apps       => [                      # optional
        {
            coordinate => '31990:pubkey:id',  # required
            relay      => 'wss://...',        # optional (SHOULD)
            platform   => 'web',              # optional (SHOULD)
        },
    ],
);

Creates a kind 31989 recommendation Net::Nostr::Event. pubkey and event_kind are required. Each app in the apps arrayref becomes an a tag. The relay and platform fields are optional but SHOULD be included per spec.

handler

my $event = Net::Nostr::AppHandler->handler(
    pubkey     => $hex_pubkey,           # required
    identifier => 'my-app',             # required (d tag)
    kinds      => ['31337', '30023'],   # required (k tags)
    content    => '{"name":"App"}',     # optional (kind:0-style JSON)
    platforms  => [                     # optional
        { platform => 'web', url => 'https://app.com/<bech32>', entity => 'nevent' },
        { platform => 'ios', url => 'com.app:///<bech32>' },
    ],
);

Creates a kind 31990 handler information Net::Nostr::Event. pubkey, identifier, and kinds are required.

The content field is an optional stringified JSON object with kind:0-style metadata. If empty, clients should use the pubkey's kind:0 profile instead.

Each entry in platforms becomes a platform tag. The entity field is an optional NIP-19 entity type (e.g. nevent, nprofile). A platform tag without an entity type is a generic handler for any NIP-19 entity.

client_tag

my $tag = Net::Nostr::AppHandler->client_tag(
    name       => 'My Client',                # required
    coordinate => '31990:pubkey:identifier',  # required
    relay      => 'wss://relay.com',          # optional
);

Creates a client tag arrayref suitable for inclusion in any event's tags. name and coordinate are required; croaks if either is missing. Clients MAY include this tag to identify themselves. This has privacy implications, so clients SHOULD allow users to opt out.

my $event = Net::Nostr::Event->new(
    kind    => 1,
    pubkey  => $pubkey,
    content => 'Hello!',
    tags    => [$tag],
);

from_event

my $info = Net::Nostr::AppHandler->from_event($event);

Parses a kind 31989 or 31990 Net::Nostr::Event. Returns a Net::Nostr::AppHandler object with accessors, or undef if the event is not a handler kind.

For kind 31989 (recommendation), the returned object has event_kind and apps accessors.

For kind 31990 (handler), the returned object has identifier, kinds, content, and platforms accessors.

validate

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

Validates that an event is a well-formed NIP-89 event. Croaks if:

  • Kind is not 31989 or 31990

  • Missing d tag

  • Kind 31990 missing k tag

recommendation_filter

my $filter = Net::Nostr::AppHandler->recommendation_filter(
    event_kind => '31337',
    authors    => [$user_pk, @follows],
);

Returns a hashref suitable for use as a Nostr filter to query for recommendations for a given event kind.

handler_filter

my $filter = Net::Nostr::AppHandler->handler_filter(
    event_kind => '31337',
    authors    => [$app_pk],
);

Returns a hashref suitable for use as a Nostr filter to query for handler information for a given event kind.

ACCESSORS

These are available on objects returned by "from_event".

event_kind

my $kind = $info->event_kind;  # '31337'

The event kind being recommended (from the d tag of kind 31989).

apps

my $apps = $info->apps;
# [{ coordinate => '31990:pk:id', relay => 'wss://...', platform => 'web' }]

Arrayref of hashrefs describing recommended apps (from a tags of kind 31989). Each hashref has a coordinate key, and optional relay and platform keys.

identifier

my $id = $info->identifier;

The d tag value identifying the handler (kind 31990).

kinds

my $kinds = $info->kinds;  # ['31337', '30023']

Arrayref of supported event kind strings (from k tags of kind 31990).

content

my $json = $info->content;  # '{"name":"Zapstr"}' or ''

The handler's metadata content (kind:0-style JSON string), or empty string.

platforms

my $platforms = $info->platforms;
# [{ platform => 'web', url => 'https://.../<bech32>', entity => 'nevent' }]

Arrayref of hashrefs describing platform handlers (kind 31990). Each hashref has platform and url keys. The entity key is optional and specifies the NIP-19 entity type the URL handles.

SEE ALSO

NIP-89, Net::Nostr, Net::Nostr::Event