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.
| Driver | Descripción |
|---|
native | Implementación que funciona solo con PHP. Usa nostr-php. Actualmente es suficiente. |
node | Implementació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'),
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
Instala el paquete
composer require revolution/laravel-nostr
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://']);