Saltar al contenido principal

Descripción general

El Facade Bluesky es una capa fina sobre BlueskyManager. BlueskyManager gestiona varios Agents, y el trait HasShortHand agrupa los atajos de los métodos que se usan con más frecuencia.

Arquitectura

BlueskyServiceProvider registra Factory::class como BlueskyManager con un singleton scoped (una instancia por petición).
// BlueskyServiceProvider::register()
$this->app->scoped(Factory::class, BlueskyManager::class);
El getFacadeAccessor() del Facade resuelve este binding.
// Facades/Bluesky.php
protected static function getFacadeAccessor(): string
{
    return Factory::class;
}

Métodos principales de BlueskyManager

A continuación se listan los métodos principales que define el propio BlueskyManager. Distinguirlos de los métodos del trait HasShortHand ayuda a entender la estructura interna.

Autenticación

MétodoDescripción
login(string $identifier, string $password, ?string $service = null)Autentica con App Password y configura un LegacyAgent
withToken(?AbstractSession $token)Recibe un OAuthSession o LegacySession y configura el Agent
check(): boolComprueba si hay autenticación (también verifica la vigencia del token)
refreshSession()Refresca los tokens
logout()Limpia el Agent

Operaciones del Agent

MétodoDescripción
agent(): ?AgentObtiene el Agent actual
withAgent(?Agent $agent)Configura el Agent directamente
assertDid(): stringDevuelve el DID autenticado. Lanza una excepción si no está autenticado

Cliente HTTP

MétodoDescripción
client(bool $auth = true): AtpClientDevuelve un cliente XRPC autenticado (o anónimo)
public(): BskyClientDevuelve un cliente de endpoints públicos sin autenticación
send(BackedEnum|string $api, string $method, bool $auth, ?array $params, ?callable $callback)Invoca directamente cualquier API del AT Protocol

Utilidades

MétodoDescripción
identity(): IdentityObtiene el servicio de identidad para resolver DIDs, etc.
pds(): PDSObtiene el servicio de información de PDS
entryway(?string $path): stringDevuelve la URL del servicio (por ejemplo bsky.social)
publicEndpoint(): stringDevuelve la URL del endpoint público

Trait HasShortHand

El trait HasShortHand envuelve las APIs de bajo nivel del AT Protocol en métodos claros y orientados a PHP. Basta con añadir use HasShortHand; en BlueskyManager para que estos métodos puedan invocarse directamente desde Bluesky::.
// BlueskyManager.php
class BlueskyManager implements Factory
{
    use Conditionable;
    use HasShortHand;
    use Macroable;
    // ...
}
HasShortHand se mantiene como un trait independiente para facilitar las pruebas y la personalización. Gracias a este trait, el código de BlueskyManager sigue siendo simple mientras se ofrece un amplio conjunto de atajos de API.

Publicaciones y feed

MétodoDescripción
post(Post|string|array $text)Crea una nueva publicación
getPost(string $uri)Obtiene una publicación a partir de su AT-URI
getPosts(array $uris)Obtiene varias publicaciones a la vez
deletePost(string $uri)Elimina una publicación
getTimeline(?string $algorithm, ?int $limit, ?string $cursor)Obtiene la timeline de inicio
getAuthorFeed(?string $actor, ...)Obtiene el feed de la cuenta indicada
searchPosts(string $q, ...)Busca publicaciones

Interacciones

MétodoDescripción
like(Like|StrongRef $subject)Crea un like
deleteLike(string $uri)Elimina un like
repost(Repost|StrongRef $subject)Crea un repost
deleteRepost(string $uri)Elimina un repost
getActorLikes(?string $actor, ...)Obtiene la lista de likes de la cuenta

Follow

MétodoDescripción
follow(Follow|string $did)Follow
deleteFollow(string $uri)Deshace el follow
getFollowers(?string $actor, ...)Obtiene la lista de followers
getFollows(?string $actor, ...)Obtiene la lista de following

Perfil y cuenta

MétodoDescripción
getProfile(?string $actor)Obtiene el perfil
upsertProfile(callable $callback)Actualiza el perfil
resolveHandle(string $handle)Resuelve un handle a DID

Multimedia

MétodoDescripción
uploadBlob(StreamInterface|string $data, string $type)Sube blobs como imágenes
uploadVideo(StreamInterface|string $data, string $type)Sube un vídeo
getJobStatus(string $jobId)Comprueba el estado del job de subida de vídeo
getUploadLimits()Obtiene los límites de subida

Notificaciones

MétodoDescripción
listNotifications(...)Obtiene la lista de notificaciones
countUnreadNotifications(...)Obtiene el número de notificaciones sin leer
updateSeenNotifications(string $seenAt)Actualiza el estado leído

Operaciones sobre records del AT Protocol

MétodoDescripción
createRecord(string $repo, string $collection, ...)Crea un record
getRecord(string $repo, string $collection, string $rkey, ...)Obtiene un record
listRecords(string $repo, string $collection, ...)Obtiene la lista de records
putRecord(string $repo, string $collection, string $rkey, ...)Actualiza o crea un record
deleteRecord(string $repo, string $collection, string $rkey, ...)Elimina un record

Feed generator y labeler

MétodoDescripción
publishFeedGenerator(BackedEnum|string $name, Generator $generator)Publica un feed generator
createThreadGate(string $post, ?array $allow)Crea un thread gate
upsertLabelDefinitions(callable $callback)Actualiza las definiciones de etiquetas
deleteLabelDefinitions()Elimina las definiciones de etiquetas
createLabels(RepoRef|StrongRef|array $subject, array $labels)Aplica etiquetas
deleteLabels(RepoRef|StrongRef|array $subject, array $labels)Elimina etiquetas

Ejemplos de atajos habituales

Publicar

use Revolution\Bluesky\Facades\Bluesky;

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

Responder

Para responder, configura el StrongRef de la publicación padre con Post::build(). HasShortHand no dispone de un método reply() específico; se pasa el objeto 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('texto de la respuesta')
    ->reply(root: $parent, parent: $parent);

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

Like y 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);

Actualizar el perfil

upsertProfile() obtiene el perfil actual y guarda los cambios que se realizan dentro de la clausura. Puedes usar los métodos del objeto Profile para configurar displayName, description, etc.
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Record\Profile;

Bluesky::login(config('bluesky.identifier'), config('bluesky.password'))
    ->upsertProfile(function (Profile $profile) {
        $profile->displayName('Nuevo nombre mostrado')
                ->description('Texto descriptivo del perfil');
    });

Configurar self labels

Con SelfLabels puedes aplicar self labels a toda la cuenta.
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']));
    });

Llamar directamente a una API arbitraria

Para métodos que no están en HasShortHand, usa send() o client().
use Revolution\Bluesky\Facades\Bluesky;

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

// Con client() puedes hacer operaciones más finas
$response = Bluesky::withToken($session)
    ->client()
    ->bsky()
    ->getProfiles(actors: ['did:plc:...']);

Diferencias entre usar el Facade y usarlo directamente

Bluesky::post() y app(Factory::class)->post() son operaciones sobre la misma instancia de BlueskyManager.
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Contracts\Factory;

// A través del Facade (uso habitual)
Bluesky::login(config('bluesky.identifier'), config('bluesky.password'))
    ->post('Hello');

// Obtener directamente del contenedor
$manager = app(Factory::class);
$manager->login(config('bluesky.identifier'), config('bluesky.password'))
        ->post('Hello');

// Inyección por tipo
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');
    }
}
Como el registro es scoped, dentro de una misma petición se conserva el estado de la sesión tras login().

Conditionable y Macroable

BlueskyManager también usa los traits Conditionable y 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('Publicación desde el entorno de producción');
    });

Macroable: añadir métodos personalizados

Con macro() puedes añadir métodos a BlueskyManager desde la aplicación. Es habitual definirlos dentro de boot() en AppServiceProvider.
use Revolution\Bluesky\Facades\Bluesky;

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

// Ejemplo de uso
Bluesky::login(config('bluesky.identifier'), config('bluesky.password'))
    ->postWithHashtag('Hello', 'laravel');

Inyectar un Agent personalizado

Con withAgent() puedes asignar directamente cualquier implementación de Agent.
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Contracts\Agent;

// Si implementas un Agent personalizado, implementa la interfaz Agent
class MyCustomAgent implements Agent
{
    // ...
}

Bluesky::withAgent(new MyCustomAgent());
Con la autenticación habitual (login() / withToken()) el agente se configura automáticamente, por lo que withAgent() suele usarse sobre todo en pruebas.

Enlaces de referencia

Última modificación el 13 de julio de 2026