Saltar al contenido principal

Resumen

revolution/laravel-nostr es un paquete para utilizar el protocolo Nostr desde Laravel. Ofrece generación y conversión de claves, obtención y publicación de eventos, soporte para pool (varios relays), perfiles NIP-05, mensajes directos privados NIP-17 e integración con Laravel Notifications.
Como la especificación de Nostr aún está evolucionando, este paquete también está en desarrollo continuo. Las notificaciones ya se pueden usar de forma práctica.

Drivers

Este paquete tiene 2 drivers.
DriverDescripción
nativeImplementación que funciona solo con PHP. Usa nostr-php. Actualmente es suficiente.
nodeImplementación que depende de una WebAPI externa (Node.js).
Lo característico del driver native es la implementación de WebSocketHttpMixin. Se conecta al WebSocket a través del cliente HTTP de Laravel, envía y recibe datos y se desconecta enseguida. No hace falta mantener un servidor WebSocket en ejecución, así que cualquier usuario de Laravel puede usarlo.
El driver native no admite NIP-04.

Configurar el driver por defecto

Se configura en config/nostr.php o en .env.
// config/nostr.php

'driver' => env('NOSTR_DRIVER', 'node'),
NOSTR_DRIVER=native
Si no especificas un driver, se usa el driver por defecto.
use Revolution\Nostr\Facades\Nostr;

Nostr::event()->list();
También puedes indicar el driver de forma explícita.
use Revolution\Nostr\Facades\Nostr;

Nostr::driver('node')->event()->list();
Nostr::node()->event()->list();

Nostr::driver('native')->event()->list();
Nostr::native()->event()->list();

Instalación

1

Instala el paquete

composer require revolution/laravel-nostr
2

Publica el archivo de configuración

php artisan vendor:publish --tag=nostr-config

Gestión de claves

Generar claves

use Revolution\Nostr\Facades\Nostr;
use Illuminate\Http\Client\Response;

/** @var Response $response */
$response = Nostr::key()->generate();
$keys = $response->json();
// [
//     'sk'   => 'sk...',
//     'nsec' => 'nsec...',
//     'pk'   => 'pk...',
//     'npub' => 'npub...',
// ]

Convertir claves

Conversión desde nsec.
use Revolution\Nostr\Facades\Nostr;

$response = Nostr::key()->fromNsec(nsec: 'nsec');
$keys = $response->json();
// ['sk' => '...', 'nsec' => '...', 'pk' => '...', 'npub' => '...']
Conversión desde la Secret Key.
$response = Nostr::key()->fromSecretKey(sk: 'sk');
Conversión desde npub (solo clave pública).
$response = Nostr::key()->fromNpub(npub: 'npub');
$keys = $response->json();
// ['pk' => '...', 'npub' => '...']
Conversión desde la Public Key.
$response = Nostr::key()->fromPublicKey(pk: 'pk');

Obtención de eventos

Obtener varios eventos

use Illuminate\Http\Client\Response;
use Revolution\Nostr\Facades\Nostr;
use Revolution\Nostr\Filter;
use Revolution\Nostr\Kind;

$filter = Filter::make(
    authors: ['my pk'],
    kinds: [Kind::Text],
    limit: 10,
);

/** @var Response $response */
$response = Nostr::event()->list(filter: $filter);
$events = $response->json('events');
// [
//     ['id' => '...1', 'kind' => 1, 'content' => '...'],
//     ['id' => '...2', 'kind' => 1, 'content' => '...'],
// ]

Obtener un solo evento

use Revolution\Nostr\Facades\Nostr;
use Revolution\Nostr\Filter;
use Revolution\Nostr\Kind;

$filter = Filter::make(
    authors: ['my pk'],
    kinds: [Kind::Metadata],
);

$response = Nostr::event()->get(filter: $filter);
$event = $response->json('event');
// ['id' => '...', 'kind' => 0, 'content' => '{name: ""}']

Publicación de eventos

Publicar en un solo relay

use Revolution\Nostr\Facades\Nostr;
use Revolution\Nostr\Event;
use Revolution\Nostr\Kind;

$event = Event::make(
    kind: Kind::Text,
    content: 'hello',
    created_at: now()->timestamp,
    tags: [],
);

$sk = 'my sk';

$response = Nostr::event()->publish(event: $event, sk: $sk);

if ($response->successful()) {
    $event = $response->json('event');
}

Publicar en varios relays (pool)

use Revolution\Nostr\Facades\Nostr;
use Revolution\Nostr\Event;
use Revolution\Nostr\Kind;

$event = Event::make(
    kind: Kind::Text,
    content: 'test',
    created_at: now()->timestamp,
    tags: [],
);

$responses = Nostr::pool()->publish(event: $event, sk: 'my sk');
// $responses es array<string, Response>
// ['wss://relay1' => $response, 'wss://relay2' => $response]

foreach ($responses as $relay => $response) {
    if ($response->failed()) {
        dump($relay . ' : ' . $response->body());
    }
}

Configuración de los servidores relay

Servidores relay utilizados

Si utilizas solo Nostr::event(), se usa el primer relay de config/nostr.php. Con Nostr::pool() se usan todos los relays de la configuración.

Cambiar el relay en tiempo de ejecución

use Revolution\Nostr\Facades\Nostr;

$response = Nostr::event()->withRelay('wss://')->...;
use Revolution\Nostr\Facades\Nostr;

$response = Nostr::pool()->withRelays(['wss://', 'wss://'])->...;

Perfil NIP-05

use Revolution\Nostr\Facades\Nostr;

$profile = Nostr::nip05()->profile('user@localhost');
// [
//     'user'   => 'user@localhost',
//     'pubkey' => 'pk',
//     'relays' => [],
// ]

Mensajes directos privados NIP-17

NIP-17 solo está disponible en el driver native.

Enviar un mensaje privado

use Revolution\Nostr\Facades\Nostr;

$response = Nostr::driver('native')
    ->nip17()
    ->sendDirectMessage(
        sk: 'sender-secret-key',
        pk: 'receiver-public-key',
        message: 'Hello, this is a private message!'
    );

Descifrar un mensaje privado

use Revolution\Nostr\Facades\Nostr;

$response = Nostr::driver('native')
    ->nip17()
    ->decryptDirectMessage(
        giftWrap: $receivedGiftWrap,
        sk: 'receiver-secret-key'
    );

$decryptedMessage = $response->json();

Laravel Notifications

Con NostrChannel puedes enviar mensajes a Nostr desde Laravel Notifications.

Clase Notification

use Illuminate\Notifications\Notification;
use Revolution\Nostr\Notifications\NostrChannel;
use Revolution\Nostr\Notifications\NostrMessage;
use Revolution\Nostr\Tags\HashTag;

class TestNotification extends Notification
{
    public function via(object $notifiable): array
    {
        return [
            'mail',
            NostrChannel::class,
        ];
    }

    public function toNostr(object $notifiable): NostrMessage
    {
        return new NostrMessage(
            // El #laravel dentro de content es para visualización; el HashTag en tags es para categorización a nivel de protocolo.
            content: 'hello #laravel',
            tags: [
                HashTag::make(t: 'laravel'),
            ],
        );
    }
}

Notificación bajo demanda

use Illuminate\Support\Facades\Notification;
use Revolution\Nostr\Notifications\NostrRoute;

Notification::route('nostr', NostrRoute::to(sk: 'sk'))
    ->notify(new TestNotification());

Integración con el modelo User

use Illuminate\Notifications\Notifiable;
use Revolution\Nostr\Notifications\NostrRoute;

class User
{
    use Notifiable;

    public function routeNotificationForNostr($notification): NostrRoute
    {
        return NostrRoute::to(sk: $this->sk, relays: ['wss://']);
    }
}
$user->notify(new TestNotification());

Servidores relay usados en las notificaciones

Por defecto se usan todos los relays de config/nostr.php. Si indicas relays en NostrRoute puedes cambiarlos en tiempo de ejecución.
use Revolution\Nostr\Notifications\NostrRoute;

return NostrRoute::to(sk: 'sk', relays: ['wss://', 'wss://']);
Para la información más reciente, consulta el repositorio de GitHub.
Última modificación el 13 de julio de 2026