Vai al contenuto principale

Panoramica

La Facade Bluesky è un wrapper sottile su BlueskyManager. BlueskyManager gestisce più agenti e il trait HasShortHand raccoglie in un unico posto le scorciatoie ai metodi più frequenti.

Architettura

BlueskyServiceProvider registra Factory::class come BlueskyManager in un singleton scoped (una istanza per richiesta).
// BlueskyServiceProvider::register()
$this->app->scoped(Factory::class, BlueskyManager::class);
Il getFacadeAccessor() della Facade risolve questo binding.
// Facades/Bluesky.php
protected static function getFacadeAccessor(): string
{
    return Factory::class;
}

Metodi core di BlueskyManager

I metodi core definiti da BlueskyManager stesso sono i seguenti. Distinguerli dai metodi del trait HasShortHand aiuta a comprendere la struttura interna.

Autenticazione

MetodoDescrizione
login(string $identifier, string $password, ?string $service = null)Autentica con App Password e imposta un LegacyAgent
withToken(?AbstractSession $token)Passa una OAuthSession o LegacySession e imposta l’Agent
check(): boolVerifica se sei autenticato (controlla anche la scadenza del token)
refreshSession()Rinnova il token
logout()Rimuove l’Agent

Operazioni sull’Agent

MetodoDescrizione
agent(): ?AgentOttieni l’Agent corrente
withAgent(?Agent $agent)Imposta direttamente un Agent
assertDid(): stringRestituisce il DID autenticato. Lancia un’eccezione se non sei autenticato

Client HTTP

MetodoDescrizione
client(bool $auth = true): AtpClientRestituisce un client XRPC autenticato (o anonimo)
public(): BskyClientRestituisce un client per gli endpoint pubblici senza autenticazione
send(BackedEnum|string $api, string $method, bool $auth, ?array $params, ?callable $callback)Invoca direttamente qualsiasi API AT Protocol

Utility

MetodoDescrizione
identity(): IdentityOttiene il servizio identity (risoluzione DID, ecc.)
pds(): PDSOttiene il servizio di informazioni PDS
entryway(?string $path): stringRestituisce l’URL del servizio (es. bsky.social)
publicEndpoint(): stringRestituisce l’URL dell’endpoint pubblico

Trait HasShortHand

Il trait HasShortHand incapsula API di basso livello di AT Protocol in metodi PHP più chiari. Basta scrivere use HasShortHand; in BlueskyManager per rendere questi metodi invocabili direttamente da Bluesky::.
// BlueskyManager.php
class BlueskyManager implements Factory
{
    use Conditionable;
    use HasShortHand;
    use Macroable;
    // ...
}
Il motivo per cui HasShortHand è un trait indipendente è la facilità di test e personalizzazione. Grazie a questo trait, il codice di BlueskyManager resta semplice pur fornendo un ampio ventaglio di shortcut API.

Post e feed

MetodoDescrizione
post(Post|string|array $text)Crea un nuovo post
getPost(string $uri)Recupera un post tramite AT-URI
getPosts(array $uris)Recupera più post in una sola volta
deletePost(string $uri)Elimina un post
getTimeline(?string $algorithm, ?int $limit, ?string $cursor)Ottiene la home timeline
getAuthorFeed(?string $actor, ...)Ottiene il feed dell’account specificato
searchPosts(string $q, ...)Cerca post

Engagement

MetodoDescrizione
like(Like|StrongRef $subject)Crea un like
deleteLike(string $uri)Rimuove il like
repost(Repost|StrongRef $subject)Crea un repost
deleteRepost(string $uri)Rimuove il repost
getActorLikes(?string $actor, ...)Ottiene l’elenco dei like di un account

Follow

MetodoDescrizione
follow(Follow|string $did)Segui
deleteFollow(string $uri)Smetti di seguire
getFollowers(?string $actor, ...)Ottiene l’elenco dei follower
getFollows(?string $actor, ...)Ottiene l’elenco degli account seguiti

Profilo e account

MetodoDescrizione
getProfile(?string $actor)Ottiene il profilo
upsertProfile(callable $callback)Aggiorna il profilo
resolveHandle(string $handle)Risolve un handle in un DID

Media

MetodoDescrizione
uploadBlob(StreamInterface|string $data, string $type)Carica un blob (immagine, ecc.)
uploadVideo(StreamInterface|string $data, string $type)Carica un video
getJobStatus(string $jobId)Verifica lo stato del job di upload video
getUploadLimits()Ottiene i limiti di upload

Notifiche

MetodoDescrizione
listNotifications(...)Ottiene l’elenco delle notifiche
countUnreadNotifications(...)Ottiene il conteggio delle notifiche non lette
updateSeenNotifications(string $seenAt)Aggiorna lo stato di lettura

Operazioni sui record AT Protocol

MetodoDescrizione
createRecord(string $repo, string $collection, ...)Crea un record
getRecord(string $repo, string $collection, string $rkey, ...)Recupera un record
listRecords(string $repo, string $collection, ...)Ottiene l’elenco dei record
putRecord(string $repo, string $collection, string $rkey, ...)Aggiorna o crea un record
deleteRecord(string $repo, string $collection, string $rkey, ...)Elimina un record

Feed generator e labeler

MetodoDescrizione
publishFeedGenerator(BackedEnum|string $name, Generator $generator)Pubblica un feed generator
createThreadGate(string $post, ?array $allow)Crea un thread gate
upsertLabelDefinitions(callable $callback)Aggiorna le definizioni delle label
deleteLabelDefinitions()Elimina le definizioni delle label
createLabels(RepoRef|StrongRef|array $subject, array $labels)Assegna label
deleteLabels(RepoRef|StrongRef|array $subject, array $labels)Rimuove label

Esempi di shortcut di uso frequente

Pubblicare un post

use Revolution\Bluesky\Facades\Bluesky;

$response = Bluesky::login(
    identifier: config('bluesky.identifier'),
    password: config('bluesky.password'),
)->post('Hello Bluesky');

Rispondere

Nelle risposte imposta lo StrongRef del post genitore tramite Post::build(). In HasShortHand non c’è un metodo reply() dedicato: passi un oggetto Post a post().
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Record\Post;
use Revolution\Bluesky\Types\StrongRef;

$parent = StrongRef::to(uri: 'at://did:plc:.../app.bsky.feed.post/...', cid: 'bafyrei...');

$reply = Post::create('Testo della risposta')
    ->reply(root: $parent, parent: $parent);

Bluesky::login(config('bluesky.identifier'), config('bluesky.password'))
    ->post($reply);

Like e repost

use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Types\StrongRef;

$ref = StrongRef::to(uri: 'at://did:plc:.../app.bsky.feed.post/...', cid: 'bafyrei...');

// Like
Bluesky::withToken($session)->like($ref);

// Repost
Bluesky::withToken($session)->repost($ref);

Aggiornare il profilo

upsertProfile() recupera il profilo attuale e salva le modifiche apportate dentro la closure. Puoi usare i metodi dell’oggetto Profile per impostare displayName, description e altro.
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Record\Profile;

Bluesky::login(config('bluesky.identifier'), config('bluesky.password'))
    ->upsertProfile(function (Profile $profile) {
        $profile->displayName('Nuovo nome visualizzato')
                ->description('Testo di descrizione del profilo');
    });

Impostare self-label

Con SelfLabels puoi impostare self-label per l’intero account.
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Record\Profile;
use Revolution\Bluesky\Types\SelfLabels;

Bluesky::login(config('bluesky.identifier'), config('bluesky.password'))
    ->upsertProfile(function (Profile $profile) {
        $profile->labels(SelfLabels::make(['!no-unauthenticated']));
    });

Invocare direttamente un’API arbitraria

Per i metodi non presenti in HasShortHand, usa send() o client().
use Revolution\Bluesky\Facades\Bluesky;

// Invoca un metodo XRPC arbitrario con send()
$response = Bluesky::withToken($session)
    ->send(
        api: 'app.bsky.actor.getProfiles',
        method: 'get',
        params: ['actors' => ['did:plc:...', 'did:plc:...']],
    );

// Con client() hai un controllo più fine
$response = Bluesky::withToken($session)
    ->client()
    ->bsky()
    ->getProfiles(actors: ['did:plc:...']);

Differenza tra utilizzo via Facade e utilizzo diretto

Bluesky::post() e app(Factory::class)->post() operano sulla stessa istanza di BlueskyManager.
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Contracts\Factory;

// Via Facade (uso classico)
Bluesky::login(config('bluesky.identifier'), config('bluesky.password'))
    ->post('Hello');

// Recupero diretto dal container
$manager = app(Factory::class);
$manager->login(config('bluesky.identifier'), config('bluesky.password'))
        ->post('Hello');

// DI tramite type-hint
class MyService
{
    public function __construct(private Factory $bluesky) {}

    public function doPost(): void
    {
        $this->bluesky->login(
            config('bluesky.identifier'),
            config('bluesky.password'),
        )->post('Hello from DI');
    }
}
Grazie alla registrazione scoped, all’interno di una singola richiesta lo stato della sessione dopo login() viene mantenuto.

Conditionable e Macroable

BlueskyManager utilizza anche i trait Conditionable e Macroable.

Conditionable: when() / unless()

use Revolution\Bluesky\Facades\Bluesky;

Bluesky::login(config('bluesky.identifier'), config('bluesky.password'))
    ->when(config('app.env') === 'production', function ($bluesky) {
        $bluesky->post('Post dall\'ambiente di produzione');
    });

Macroable: aggiungere metodi personalizzati

Con macro() puoi aggiungere metodi a BlueskyManager dal lato applicazione. È tipico definirli nel boot() di AppServiceProvider.
use Revolution\Bluesky\Facades\Bluesky;

Bluesky::macro('postWithHashtag', function (string $text, string $tag) {
    /** @var \Revolution\Bluesky\BlueskyManager $this */
    return $this->post("{$text} #{$tag}");
});

// Esempio di utilizzo
Bluesky::login(config('bluesky.identifier'), config('bluesky.password'))
    ->postWithHashtag('Hello', 'laravel');

Iniettare un Agent personalizzato

Con withAgent() puoi impostare direttamente una qualsiasi implementazione di Agent.
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Contracts\Agent;

// Per implementare un Agent personalizzato, implementa l'interfaccia Agent
class MyCustomAgent implements Agent
{
    // ...
}

Bluesky::withAgent(new MyCustomAgent());
Con l’autenticazione normale (login() / withToken()) l’agente viene impostato automaticamente, quindi le occasioni per usare direttamente withAgent() sono principalmente in fase di test.
Ultima modifica il 13 luglio 2026