跳转到主要内容

概览

laravel-bluesky 可以集成到 Laravel 的 Notification 系统中。通过 BlueskyChannel 可以发送普通帖子,通过 BlueskyPrivateChannel 可以发送私信(DM)。

可用通道

通道用途
BlueskyChannel以普通公开帖子的形式通知
BlueskyPrivateChannel以 DM(私聊)的形式发送给接收者

Notification 类

BlueskyChannel

via() 中指定 BlueskyChannel::class,通过 toBluesky() 返回发送内容。
use Illuminate\Notifications\Notification;
use Revolution\Bluesky\Notifications\BlueskyChannel;
use Revolution\Bluesky\Record\Post;
use Revolution\Bluesky\RichText\TextBuilder;
use Revolution\Bluesky\Embed\External;

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

    public function toBluesky(object $notifiable): Post
    {
        $external = External::create(title: 'Title', description: 'test', uri: 'https://');

        return Post::build(function (TextBuilder $builder) {
                   $builder->text('test')
                           ->newLine()
                           ->tag('#Laravel');
        })->embed($external);
    }
}
Post 的使用方式与 Basic client 相同。TextBuilder、Embed 等也可以按同样的方式使用。

BlueskyPrivateChannel

BlueskyPrivateMessagePost 几乎一样,但只支持 text、facets、embed。其中 embed 仅支持 QuoteRecord
use Illuminate\Notifications\Notification;
use Revolution\Bluesky\Notifications\BlueskyPrivateChannel;
use Revolution\Bluesky\Notifications\BlueskyPrivateMessage;
use Revolution\Bluesky\RichText\TextBuilder;
use Revolution\Bluesky\Embed\QuoteRecord;
use Revolution\Bluesky\Types\StrongRef;

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

    public function toBlueskyPrivate(object $notifiable): BlueskyPrivateMessage
    {
        $quote = QuoteRecord::create(StrongRef::to(uri: 'at://', cid: 'cid'));

        return BlueskyPrivateMessage::build(function (TextBuilder $builder) {
                   $builder->text('test')
                           ->newLine()
                           ->tag('#Laravel');
        })->embed($quote);
    }
}

即时通知

如果不使用模型,需要临时指定接收方,可以使用 Notification::route()

BlueskyChannel

use Illuminate\Support\Facades\Notification;
use Revolution\Bluesky\Notifications\BlueskyRoute;
use Revolution\Bluesky\Session\OAuthSession;
use App\Models\User;

// App password
Notification::route('bluesky', BlueskyRoute::to(identifier: config('bluesky.identifier'), password: config('bluesky.password')))
            ->notify(new TestNotification());

// OAuth
$user = User::find(1);
$session = OAuthSession::create([
    'did' => $user->did,
    'iss' => $user->iss,
    'refresh_token' => $user->refresh_token,
]);
Notification::route('bluesky', BlueskyRoute::to(oauth: $session))
            ->notify(new TestNotification());

BlueskyPrivateChannel

DM 必须指定 receiver(发送目标的 DID 或 handle)。此外,接收者一侧也需要允许接收 DM。
  • App password 时,需要拥有发送 DM 的权限。
  • OAuth 时,需要 transition:chat.bsky 权限。
use Illuminate\Support\Facades\Notification;
use Revolution\Bluesky\Notifications\BlueskyRoute;
use Revolution\Bluesky\Session\OAuthSession;
use App\Models\User;

// App password
Notification::route('bluesky-private', BlueskyRoute::to(identifier: config('bluesky.identifier'), password: config('bluesky.password'), receiver: 'did or handle'))
            ->notify(new TestNotification());

// OAuth
$user = User::find(1);
$session = OAuthSession::create([
    'did' => $user->did,
    'iss' => $user->iss,
    'refresh_token' => $user->refresh_token,
]);
Notification::route('bluesky-private', BlueskyRoute::to(oauth: $session, receiver: 'did or handle'))
            ->notify(new TestNotification());
在 Bluesky 中不能给自己发送 DM。如果想给自己发通知,请另外准备一个发送用账号。
// 给自己发送 DM 的场景

use Illuminate\Support\Facades\Notification;
use Revolution\Bluesky\Notifications\BlueskyRoute;

Notification::route('bluesky-private', BlueskyRoute::to(identifier: 'sender identifier', password: 'sender password', receiver: 'your did or handle'))
            ->notify(new TestNotification());
个人使用等场景下,如果发送者和接收者一直固定,可以在 .env 中配置。请为此专门创建一个发送账号。
BLUESKY_SENDER_IDENTIFIER=sender did or handle
BLUESKY_SENDER_APP_PASSWORD=sender password
BLUESKY_RECEIVER=your did or handle
Notification::route('bluesky-private', BlueskyRoute::to(
    identifier: config('bluesky.notification.private.sender.identifier'),
    password: config('bluesky.notification.private.sender.password'),
    receiver: config('bluesky.notification.private.receiver'),
))->notify(new TestNotification());

用户通知

在使用 Notifiable trait 的模型上定义通知路由。

BlueskyChannel

use Illuminate\Notifications\Notifiable;
use Revolution\Bluesky\Notifications\BlueskyRoute;
use Revolution\Bluesky\Session\OAuthSession;

class User
{
    use Notifiable;

    public function routeNotificationForBluesky($notification): BlueskyRoute
    {
        // App password
        return BlueskyRoute::to(identifier: $this->bluesky_identifier, password: $this->bluesky_password);

        // OAuth
        $session = OAuthSession::create([
            'did' => $this->did,
            'iss' => $this->iss,
            'refresh_token' => $this->refresh_token,
        ]);
        return BlueskyRoute::to(oauth: $session);
    }
}

$user->notify(new TestNotification());

BlueskyPrivateChannel

use Illuminate\Notifications\Notifiable;
use Revolution\Bluesky\Notifications\BlueskyRoute;
use Revolution\Bluesky\Session\OAuthSession;

class User
{
    use Notifiable;

    public function routeNotificationForBlueskyPrivate($notification): BlueskyRoute
    {
        // App password
        return BlueskyRoute::to(identifier: $this->bluesky_identifier, password: $this->bluesky_password, receiver: $this->receiver);

        // OAuth
        $session = OAuthSession::create([
            'did' => $this->did,
            'iss' => $this->iss,
            'refresh_token' => $this->refresh_token,
        ]);
        return BlueskyRoute::to(oauth: $session, receiver: $this->receiver);
    }
}

$user->notify(new TestNotification());
也可以把用户自己设为接收者。
public function routeNotificationForBlueskyPrivate($notification): BlueskyRoute
{
    // App password
    return BlueskyRoute::to(identifier: 'sender identifier', password: 'sender password', receiver: $this->did);
}

BlueskyRoute

根据认证方式(App password 或 OAuth)指定方式不同。建议使用具名参数。
use Revolution\Bluesky\Notifications\BlueskyRoute;
use Revolution\Bluesky\Session\OAuthSession;

// App password
BlueskyRoute::to(identifier: config('bluesky.identifier'), password: config('bluesky.password'))

// OAuth
$session = OAuthSession::create([
    'did' => '...',
    'iss' => '...',
    'refresh_token' => '...',
]);
BlueskyRoute::to(oauth: $session);
如果只是给自己的账号发通知,App password 是最简单的方式。你不需要考虑 refresh_token 的更新,只要配置好 .env 就能使用。
BLUESKY_IDENTIFIER=
BLUESKY_APP_PASSWORD=

查看通知结果

和普通的 Laravel 一样,可以通过 NotificationSent 事件查看通知后的响应。
use Illuminate\Notifications\Events\NotificationSent;
use Illuminate\Http\Client\Response;

class Listener
{
    public function handle(NotificationSent $event): void
    {
        // $event->channel  BlueskyChannel
        // $event->notifiable
        // $event->notification
        // $event->response  null|Response
    }
}
最后修改于 2026年7月13日