Passer au contenu principal

Vue d’ensemble

revolution/laravel-nostr est un package qui permet d’utiliser le protocole Nostr depuis Laravel. Il propose la génération et la conversion de clés, la récupération et la publication d’événements, la prise en charge de pools (plusieurs relays), les profils NIP-05, les messages directs privés NIP-17, ainsi que l’intégration avec Laravel Notifications.
Les spécifications de Nostr évoluent encore, ce package est donc en développement continu. La fonctionnalité de notification est déjà utilisable en pratique.

Pilotes

Ce package propose deux pilotes.
PiloteDescription
nativeImplémentation en PHP pur. Utilise nostr-php. Suffisant à l’heure actuelle.
nodeImplémentation dépendant d’une WebAPI externe (Node.js).
La particularité du pilote native est son implémentation WebSocketHttpMixin. Il se connecte en WebSocket via le client HTTP de Laravel, échange des données puis se déconnecte immédiatement. Il n’est pas nécessaire de faire tourner un serveur WebSocket en continu, ce qui rend cette solution accessible à tout utilisateur de Laravel.
Le pilote native ne prend pas en charge NIP-04.

Configuration du pilote par défaut

Configurez dans config/nostr.php ou .env.
// config/nostr.php

'driver' => env('NOSTR_DRIVER', 'node'),
NOSTR_DRIVER=native
Si aucun pilote n’est spécifié, le pilote par défaut est utilisé.
use Revolution\Nostr\Facades\Nostr;

Nostr::event()->list();
Vous pouvez également spécifier explicitement le pilote.
use Revolution\Nostr\Facades\Nostr;

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

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

Installation

1

Installer le package

composer require revolution/laravel-nostr
2

Publier le fichier de configuration

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

Gestion des clés

Générer une clé

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 une clé

Conversion depuis un nsec.
use Revolution\Nostr\Facades\Nostr;

$response = Nostr::key()->fromNsec(nsec: 'nsec');
$keys = $response->json();
// ['sk' => '...', 'nsec' => '...', 'pk' => '...', 'npub' => '...']
Conversion depuis une secret key.
$response = Nostr::key()->fromSecretKey(sk: 'sk');
Conversion depuis un npub (clé publique uniquement).
$response = Nostr::key()->fromNpub(npub: 'npub');
$keys = $response->json();
// ['pk' => '...', 'npub' => '...']
Conversion depuis une public key.
$response = Nostr::key()->fromPublicKey(pk: 'pk');

Récupération d’événements

Récupérer plusieurs événements

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' => '...'],
// ]

Récupérer un seul événement

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: ""}']

Publication d’événements

Publier sur un seul 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');
}

Publier sur plusieurs 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 est de type array<string, Response>
// ['wss://relay1' => $response, 'wss://relay2' => $response]

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

Configuration des serveurs relay

Serveurs relay utilisés

Si vous utilisez uniquement Nostr::event(), le premier relay défini dans config/nostr.php est utilisé. Avec Nostr::pool(), tous les relays de la configuration sont ciblés.

Modifier les relays à l’exécution

use Revolution\Nostr\Facades\Nostr;

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

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

Profils NIP-05

use Revolution\Nostr\Facades\Nostr;

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

Messages directs privés NIP-17

NIP-17 n’est pris en charge que par le pilote native.

Envoyer un message privé

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!'
    );

Déchiffrer un message privé

use Revolution\Nostr\Facades\Nostr;

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

$decryptedMessage = $response->json();

Laravel Notifications

Avec NostrChannel, vous pouvez envoyer des messages vers Nostr depuis Laravel Notifications.

Classe 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(
            // Le #laravel dans le content sert à l'affichage ; le HashTag dans tags est destiné à la classification au niveau du protocole.
            content: 'hello #laravel',
            tags: [
                HashTag::make(t: 'laravel'),
            ],
        );
    }
}

Notification à la demande

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

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

Intégration au modèle 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());

Relays utilisés pour les notifications

Par défaut, tous les relays de config/nostr.php sont utilisés. Vous pouvez les modifier à l’exécution en spécifiant des relays dans NostrRoute.
use Revolution\Nostr\Notifications\NostrRoute;

return NostrRoute::to(sk: 'sk', relays: ['wss://', 'wss://']);
Pour les dernières informations, consultez le dépôt GitHub.
Dernière modification le 13 juillet 2026