메인 콘텐츠로 건너뛰기

개요

revolution/laravel-nostr는 Nostr 프로토콜을 Laravel에서 이용하기 위한 패키지입니다. Key 생성·변환, 이벤트의 조회·발행, pool (복수 릴레이) 대응, NIP-05 프로필, NIP-17 Private Direct Messages, 그리고 Laravel Notifications와의 통합을 제공합니다.
Nostr 사양은 아직 진화 중이므로 이 패키지도 지속적으로 개발되고 있습니다. 알림 기능은 이미 실용적으로 사용할 수 있습니다.

드라이버

이 패키지에는 2개의 드라이버가 있습니다.
드라이버설명
nativePHP만으로 동작하는 구현. nostr-php 사용. 현재는 이것으로 충분합니다.
node외부 WebAPI (Node.js)에 의존하는 구현.
native 드라이버의 독특한 점은 WebSocketHttpMixin 구현입니다. Laravel의 HTTP 클라이언트로 WebSocket에 연결하고, 데이터를 송수신하면 곧바로 연결을 끊습니다. WebSocket 서버를 계속 켜둘 필요가 없어 Laravel 사용자라면 누구나 사용할 수 있는 설계입니다.
native 드라이버는 NIP-04에 대응하지 않습니다.

기본 드라이버 설정

config/nostr.php 또는 .env에서 설정합니다.
// config/nostr.php

'driver' => env('NOSTR_DRIVER', 'node'),
NOSTR_DRIVER=native
드라이버를 지정하지 않으면 기본 드라이버가 사용됩니다.
use Revolution\Nostr\Facades\Nostr;

Nostr::event()->list();
드라이버를 명시적으로 지정할 수도 있습니다.
use Revolution\Nostr\Facades\Nostr;

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

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

설치

1

패키지 설치

composer require revolution/laravel-nostr
2

설정 파일 게시

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

Key 관리

Key 생성

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

Key 변환

nsec에서 변환합니다.
use Revolution\Nostr\Facades\Nostr;

$response = Nostr::key()->fromNsec(nsec: 'nsec');
$keys = $response->json();
// ['sk' => '...', 'nsec' => '...', 'pk' => '...', 'npub' => '...']
Secret key에서 변환합니다.
$response = Nostr::key()->fromSecretKey(sk: 'sk');
npub에서 변환합니다 (공개키만).
$response = Nostr::key()->fromNpub(npub: 'npub');
$keys = $response->json();
// ['pk' => '...', 'npub' => '...']
Public key에서 변환합니다.
$response = Nostr::key()->fromPublicKey(pk: 'pk');

이벤트 조회

여러 이벤트 조회

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

1건의 이벤트 조회

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

이벤트 발행

단일 릴레이에 발행

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

여러 릴레이에 발행 (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는 array<string, Response>
// ['wss://relay1' => $response, 'wss://relay2' => $response]

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

릴레이 서버 설정

사용되는 릴레이 서버

Nostr::event()만 사용할 경우 config/nostr.php의 첫 번째 릴레이가 사용됩니다. Nostr::pool()을 사용하는 경우 설정 내 모든 릴레이가 대상이 됩니다.

런타임에 릴레이 변경

use Revolution\Nostr\Facades\Nostr;

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

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

NIP-05 프로필

use Revolution\Nostr\Facades\Nostr;

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

NIP-17 Private Direct Messages

NIP-17은 native 드라이버에서만 지원됩니다.

프라이빗 메시지 전송

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

프라이빗 메시지 복호화

use Revolution\Nostr\Facades\Nostr;

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

$decryptedMessage = $response->json();

Laravel Notifications

NostrChannel을 사용하면 Laravel Notifications에서 Nostr로 메시지를 전송할 수 있습니다.

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(
            // content 내의 #laravel은 표시용, tags의 HashTag는 프로토콜 레벨의 분류용
            content: 'hello #laravel',
            tags: [
                HashTag::make(t: 'laravel'),
            ],
        );
    }
}

온디맨드 알림

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

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

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());

알림에서 사용하는 릴레이 서버

기본적으로 config/nostr.php의 모든 릴레이가 사용됩니다. NostrRoute에서 릴레이를 지정하면 런타임에 변경할 수 있습니다.
use Revolution\Nostr\Notifications\NostrRoute;

return NostrRoute::to(sk: 'sk', relays: ['wss://', 'wss://']);
최신 정보는 GitHub 저장소를 참조하세요.
마지막 수정일 2026년 7월 13일