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étodo | Descripció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(): bool | Comprueba si hay autenticación (también verifica la vigencia del token) |
refreshSession() | Refresca los tokens |
logout() | Limpia el Agent |
Operaciones del Agent
| Método | Descripción |
|---|
agent(): ?Agent | Obtiene el Agent actual |
withAgent(?Agent $agent) | Configura el Agent directamente |
assertDid(): string | Devuelve el DID autenticado. Lanza una excepción si no está autenticado |
Cliente HTTP
| Método | Descripción |
|---|
client(bool $auth = true): AtpClient | Devuelve un cliente XRPC autenticado (o anónimo) |
public(): BskyClient | Devuelve 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étodo | Descripción |
|---|
identity(): Identity | Obtiene el servicio de identidad para resolver DIDs, etc. |
pds(): PDS | Obtiene el servicio de información de PDS |
entryway(?string $path): string | Devuelve la URL del servicio (por ejemplo bsky.social) |
publicEndpoint(): string | Devuelve 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étodo | Descripció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étodo | Descripció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étodo | Descripció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étodo | Descripción |
|---|
getProfile(?string $actor) | Obtiene el perfil |
upsertProfile(callable $callback) | Actualiza el perfil |
resolveHandle(string $handle) | Resuelve un handle a DID |
| Método | Descripció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étodo | Descripció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étodo | Descripció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étodo | Descripció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