NAME

Net::Blossom::Client - HTTP client for Blossom servers

SYNOPSIS

use Net::Blossom::Client;

my $client = Net::Blossom::Client->new(
    server => 'https://cdn.example.com',
    auth   => sub {
        my %ctx = @_;
        return build_authorization_header(%ctx);
    },
);

my $response = $client->get_blob($sha256);
my $blob     = $client->upload_blob($bytes, type => 'image/png');
my $blobs    = $client->list_blobs($pubkey, limit => 20);

DESCRIPTION

Net::Blossom::Client sends HTTP requests to one Blossom server. It implements client support for the currently supported Blossom BUDs in this distribution, including blob get/head/upload/delete, mirror requests, media processing, upload/media preflights, blob reports, payment challenge handling, server-list fallback helpers, and list pagination.

Methods croak for invalid local arguments and unknown options. Non-success HTTP responses die with Net::Blossom::Error. 402 Payment Required responses die with Net::Blossom::PaymentRequired.

CONSTRUCTOR

new

my $client = Net::Blossom::Client->new(%args);

Required arguments:

  • server

    The Blossom server HTTP or HTTPS base URL. Query strings, fragments, and userinfo are rejected. A path prefix is allowed. Trailing slashes are removed.

Optional arguments:

  • ua

    HTTP user agent object. Defaults to HTTP::Tiny->new. The object must provide request($method, $url, \%opts) and return a hash reference with status, reason, headers, and content.

  • auth

    Authorization provider. It may be a static Authorization header string, a code reference, or an object with authorization_header(%context).

    Code references and objects receive method, url, action, and sha256. They must return the header value or undef to omit authorization.

    When the provider object exposes an action accessor (as Net::Blossom::AuthToken does), its action must match the request's action. A single fixed-action token cannot be reused across endpoints: a mismatch croaks rather than send a token whose BUD-11 t verb the server would reject.

Unknown arguments or a missing server croak.

ACCESSORS

server

Returns the normalized server base URL.

ua

Returns the user agent object.

auth

Returns the configured authorization provider.

METHODS

get_blob

my $response = $client->get_blob($sha256, %opts);

Sends GET /<sha256> and returns a Net::Blossom::Response. Success statuses are 200, 206, 307, and 308.

Options:

  • extension

    Appends .$extension to the request path. The extension must contain only letters and digits.

  • range

    Sends a Range header.

  • payment

    Hash reference of payment proof headers. See "PAYMENT PROOFS".

head_blob

my $response = $client->head_blob($sha256, %opts);

Sends HEAD /<sha256> and returns a Net::Blossom::Response. Success statuses are 200, 307, and 308. Accepts the extension option. payment is rejected because proof headers are not allowed on HEAD requests.

upload_blob

my $descriptor = $client->upload_blob($content, %opts);

Sends PUT /upload with the exact byte string in $content. Returns a Net::Blossom::BlobDescriptor parsed from the JSON response. Success statuses are 200 and 201.

Options:

  • type

    Media type for Content-Type. Defaults to application/octet-stream.

  • payment

    Hash reference of payment proof headers. See "PAYMENT PROOFS".

head_upload

my $response = $client->head_upload($content, %opts);

Sends HEAD /upload preflight headers for the given content and returns a Net::Blossom::Response. Success status is 200. payment is not allowed on HEAD requests.

The type option sets X-Content-Type and defaults to application/octet-stream.

process_media

my $descriptor = $client->process_media($content, %opts);

Sends PUT /media and returns a Net::Blossom::BlobDescriptor. Success statuses are 200 and 201. Options match upload_blob.

head_media

my $response = $client->head_media($content, %opts);

Sends HEAD /media preflight headers and returns a Net::Blossom::Response. Success status is 200. payment is not allowed on HEAD requests.

The type option sets X-Content-Type and defaults to application/octet-stream.

upload_blob_to_servers

my $descriptor = $client->upload_blob_to_servers($content, $servers, %opts);

Uploads to the first server in $servers. $servers may be a Net::Blossom::ServerList or an array reference of server base URLs. Options are passed to upload_blob.

mirror_blob

my $descriptor = $client->mirror_blob($url, %opts);

Sends PUT /mirror with a canonical JSON body containing url. Returns a Net::Blossom::BlobDescriptor. Success statuses are 200 and 201.

If the source URL contains a SHA-256 hash, that hash is passed to the auth provider as request context.

report_blob

my $response = $client->report_blob($event, %opts);

Sends PUT /report with a NIP-56 report event hash reference. Returns a Net::Blossom::Response. Any 2xx status is treated as success.

The report event is validated locally. It must be kind 1984, include lowercase hex id, pubkey, and sig fields, include scalar content, include a non-negative integer created_at, and contain at least one x tag with a lowercase SHA-256 hash.

list_blobs

my $descriptors = $client->list_blobs($pubkey, %opts);

Sends GET /list/<pubkey> and returns an array reference of Net::Blossom::BlobDescriptor objects. $pubkey must be lowercase 64-character hex.

Options cursor, limit, since, and until are sent as query parameters when defined.

delete_blob

my $response = $client->delete_blob($sha256, %opts);

Sends DELETE /<sha256> and returns a Net::Blossom::Response. Success statuses are 200 and 204. Accepts the payment option.

get_blob_from_servers

my $response = $client->get_blob_from_servers($url, $servers, %opts);

Extracts the last SHA-256 hash from $url and tries get_blob against each server in order until one succeeds. $servers may be a Net::Blossom::ServerList or an array reference of server base URLs.

If all servers return Blossom HTTP errors, the last Net::Blossom::Error is re-thrown. Non-Blossom exceptions are re-thrown immediately.

PAYMENT PROOFS

GET, PUT, and DELETE methods accept payment => \%proofs. Keys are payment method names such as cashu or lightning, optionally with an X- prefix. Values are scalar proof strings. The client sends them as X-Cashu, X-Lightning, or the matching X-* header.

Reserved payment method names reason, sha-256, content-type, and content-length are rejected.

ERRORS

Invalid local arguments and unknown method options croak. Failed HTTP responses die with Net::Blossom::Error. Payment challenges die with Net::Blossom::PaymentRequired.

Malformed JSON success bodies also croak.

SEE ALSO

Net::Blossom::AuthToken, Net::Blossom::BlobDescriptor, Net::Blossom::Error, Net::Blossom::PaymentRequired, Net::Blossom::Response, Net::Blossom::ServerList