> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# BlueskyManager et HasShortHand

> Architecture de BlueskyManager (l'implémentation derrière la facade Bluesky) et description des méthodes raccourci fournies par le trait HasShortHand.

## Vue d'ensemble

La facade `Bluesky` est une fine enveloppe autour de `BlueskyManager`. `BlueskyManager` gère plusieurs agents, et le trait `HasShortHand` regroupe les méthodes raccourci les plus fréquemment utilisées.

## Architecture

```mermaid theme={null}
graph TD
    A["Bluesky Facade<br>(Revolution\\Bluesky\\Facades\\Bluesky)"] --> B["BlueskyManager<br>(interface Factory)"]
    B --> C["trait HasShortHand<br>Ensemble de méthodes raccourci"]
    B --> D["trait Conditionable<br>when() / unless()"]
    B --> E["trait Macroable<br>macro() / mixin()"]
    B --> F{"Agent"}
    F --> G["LegacyAgent<br>(App Password)"]
    F --> H["OAuthAgent<br>(OAuth)"]
    G --> I["LegacySession"]
    H --> J["OAuthSession"]
```

Le `BlueskyServiceProvider` enregistre `Factory::class` en tant que singleton à portée limitée (une instance par requête) vers `BlueskyManager`.

```php theme={null}
// BlueskyServiceProvider::register()
$this->app->scoped(Factory::class, BlueskyManager::class);
```

Le `getFacadeAccessor()` de la facade résout ce binding.

```php theme={null}
// Facades/Bluesky.php
protected static function getFacadeAccessor(): string
{
    return Factory::class;
}
```

## Méthodes principales de BlueskyManager

Voici les méthodes principales définies par `BlueskyManager` lui-même. Les distinguer de celles du trait `HasShortHand` aide à comprendre la structure interne.

### Authentification

| Méthode                                                                | Description                                                                       |
| ---------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `login(string $identifier, string $password, ?string $service = null)` | Authentifie via App Password et installe un `LegacyAgent`                         |
| `withToken(?AbstractSession $token)`                                   | Installe un Agent à partir d'une `OAuthSession` ou d'une `LegacySession`          |
| `check(): bool`                                                        | Vérifie si la session est authentifiée (contrôle également l'expiration du token) |
| `refreshSession()`                                                     | Renouvelle les tokens                                                             |
| `logout()`                                                             | Efface l'Agent                                                                    |

### Opérations sur l'Agent

| Méthode                    | Description                                                        |
| -------------------------- | ------------------------------------------------------------------ |
| `agent(): ?Agent`          | Récupère l'Agent courant                                           |
| `withAgent(?Agent $agent)` | Installe directement un Agent                                      |
| `assertDid(): string`      | Renvoie le DID authentifié. Lance une exception si non authentifié |

### Client HTTP

| Méthode                                                                                          | Description                                                        |
| ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------ |
| `client(bool $auth = true): AtpClient`                                                           | Renvoie un client XRPC authentifié (ou anonyme)                    |
| `public(): BskyClient`                                                                           | Renvoie un client pour les endpoints publics sans authentification |
| `send(BackedEnum\|string $api, string $method, bool $auth, ?array $params, ?callable $callback)` | Appelle directement n'importe quelle API AT Protocol               |

### Utilitaires

| Méthode                           | Description                                           |
| --------------------------------- | ----------------------------------------------------- |
| `identity(): Identity`            | Récupère le service d'identité (résolution DID, etc.) |
| `pds(): PDS`                      | Récupère le service d'informations PDS                |
| `entryway(?string $path): string` | Renvoie l'URL du service (par ex. `bsky.social`)      |
| `publicEndpoint(): string`        | Renvoie l'URL de l'endpoint public                    |

## Trait HasShortHand

Le trait `HasShortHand` enveloppe les API bas niveau d'AT Protocol dans des méthodes PHP plus lisibles. Il suffit d'ajouter `use HasShortHand;` dans `BlueskyManager` pour exposer ces méthodes directement via `Bluesky::`.

```php theme={null}
// BlueskyManager.php
class BlueskyManager implements Factory
{
    use Conditionable;
    use HasShortHand;
    use Macroable;
    // ...
}
```

<Info>
  `HasShortHand` est isolé dans un trait pour faciliter les tests et la personnalisation. Ce trait permet de fournir un large éventail de raccourcis d'API tout en gardant le code de `BlueskyManager` simple.
</Info>

### Posts et flux

| Méthode                                                         | Description                          |
| --------------------------------------------------------------- | ------------------------------------ |
| `post(Post\|string\|array $text)`                               | Crée un nouveau post                 |
| `getPost(string $uri)`                                          | Récupère un post via son AT-URI      |
| `getPosts(array $uris)`                                         | Récupère plusieurs posts en une fois |
| `deletePost(string $uri)`                                       | Supprime un post                     |
| `getTimeline(?string $algorithm, ?int $limit, ?string $cursor)` | Récupère la timeline d'accueil       |
| `getAuthorFeed(?string $actor, ...)`                            | Récupère le flux d'un compte donné   |
| `searchPosts(string $q, ...)`                                   | Recherche des posts                  |

### Engagement

| Méthode                              | Description                             |
| ------------------------------------ | --------------------------------------- |
| `like(Like\|StrongRef $subject)`     | Crée un like                            |
| `deleteLike(string $uri)`            | Retire un like                          |
| `repost(Repost\|StrongRef $subject)` | Crée un repost                          |
| `deleteRepost(string $uri)`          | Retire un repost                        |
| `getActorLikes(?string $actor, ...)` | Récupère la liste des likes d'un compte |

### Follow

| Méthode                             | Description                          |
| ----------------------------------- | ------------------------------------ |
| `follow(Follow\|string $did)`       | Suivre                               |
| `deleteFollow(string $uri)`         | Ne plus suivre                       |
| `getFollowers(?string $actor, ...)` | Récupère la liste des followers      |
| `getFollows(?string $actor, ...)`   | Récupère la liste des comptes suivis |

### Profil et compte

| Méthode                             | Description             |
| ----------------------------------- | ----------------------- |
| `getProfile(?string $actor)`        | Récupère un profil      |
| `upsertProfile(callable $callback)` | Met à jour un profil    |
| `resolveHandle(string $handle)`     | Résout un handle en DID |

### Médias

| Méthode                                                    | Description                                       |
| ---------------------------------------------------------- | ------------------------------------------------- |
| `uploadBlob(StreamInterface\|string $data, string $type)`  | Téléverse un blob (image, etc.)                   |
| `uploadVideo(StreamInterface\|string $data, string $type)` | Téléverse une vidéo                               |
| `getJobStatus(string $jobId)`                              | Vérifie le statut d'un job de téléversement vidéo |
| `getUploadLimits()`                                        | Récupère les limites de téléversement             |

### Notifications

| Méthode                                   | Description                                  |
| ----------------------------------------- | -------------------------------------------- |
| `listNotifications(...)`                  | Récupère la liste des notifications          |
| `countUnreadNotifications(...)`           | Récupère le nombre de notifications non lues |
| `updateSeenNotifications(string $seenAt)` | Met à jour l'état lu                         |

### Opérations sur les enregistrements AT Protocol

| Méthode                                                             | Description                          |
| ------------------------------------------------------------------- | ------------------------------------ |
| `createRecord(string $repo, string $collection, ...)`               | Crée un enregistrement               |
| `getRecord(string $repo, string $collection, string $rkey, ...)`    | Récupère un enregistrement           |
| `listRecords(string $repo, string $collection, ...)`                | Liste les enregistrements            |
| `putRecord(string $repo, string $collection, string $rkey, ...)`    | Met à jour ou crée un enregistrement |
| `deleteRecord(string $repo, string $collection, string $rkey, ...)` | Supprime un enregistrement           |

### Feed generator et labeler

| Méthode                                                                | Description                          |
| ---------------------------------------------------------------------- | ------------------------------------ |
| `publishFeedGenerator(BackedEnum\|string $name, Generator $generator)` | Publie un feed generator             |
| `createThreadGate(string $post, ?array $allow)`                        | Crée un thread gate                  |
| `upsertLabelDefinitions(callable $callback)`                           | Met à jour les définitions de labels |
| `deleteLabelDefinitions()`                                             | Supprime les définitions de labels   |
| `createLabels(RepoRef\|StrongRef\|array $subject, array $labels)`      | Applique des labels                  |
| `deleteLabels(RepoRef\|StrongRef\|array $subject, array $labels)`      | Retire des labels                    |

## Exemples de raccourcis courants

### Publier

```php theme={null}
use Revolution\Bluesky\Facades\Bluesky;

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

### Répondre

Pour une réponse, définissez la `StrongRef` du post parent via `Post::build()`. `HasShortHand` ne dispose pas de méthode `reply()` dédiée : on passe l'objet `Post` à `post()`.

```php theme={null}
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('Texte de la réponse')
    ->reply(root: $parent, parent: $parent);

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

### Like et repost

```php theme={null}
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);
```

### Mettre à jour son profil

`upsertProfile()` récupère le profil actuel et enregistre les modifications effectuées dans la closure. Les méthodes de l'objet `Profile` permettent de définir displayName, description, etc.

```php theme={null}
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Record\Profile;

Bluesky::login(config('bluesky.identifier'), config('bluesky.password'))
    ->upsertProfile(function (Profile $profile) {
        $profile->displayName('Nouveau nom d\'affichage')
                ->description('Description du profil');
    });
```

#### Définir des self labels

Vous pouvez utiliser `SelfLabels` pour appliquer un self label à l'ensemble du compte.

```php theme={null}
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']));
    });
```

### Appeler directement une API arbitraire

Pour toute méthode absente de `HasShortHand`, utilisez `send()` ou `client()`.

```php theme={null}
use Revolution\Bluesky\Facades\Bluesky;

// send() pour appeler une méthode XRPC arbitraire
$response = Bluesky::withToken($session)
    ->send(
        api: 'app.bsky.actor.getProfiles',
        method: 'get',
        params: ['actors' => ['did:plc:...', 'did:plc:...']],
    );

// client() pour un contrôle plus fin
$response = Bluesky::withToken($session)
    ->client()
    ->bsky()
    ->getProfiles(actors: ['did:plc:...']);
```

## Différences entre l'utilisation via la facade et l'utilisation directe

`Bluesky::post()` et `app(Factory::class)->post()` opèrent sur la même instance de `BlueskyManager`.

```php theme={null}
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Contracts\Factory;

// Via la facade (usage courant)
Bluesky::login(config('bluesky.identifier'), config('bluesky.password'))
    ->post('Hello');

// Récupération directe depuis le conteneur
$manager = app(Factory::class);
$manager->login(config('bluesky.identifier'), config('bluesky.password'))
        ->post('Hello');

// DI par 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');
    }
}
```

Grâce à l'enregistrement `scoped`, l'état de session obtenu après `login()` est conservé pendant toute la requête.

## Conditionable et Macroable

`BlueskyManager` utilise également les traits `Conditionable` et `Macroable`.

### Conditionable : when() / unless()

```php theme={null}
use Revolution\Bluesky\Facades\Bluesky;

Bluesky::login(config('bluesky.identifier'), config('bluesky.password'))
    ->when(config('app.env') === 'production', function ($bluesky) {
        $bluesky->post('Publication depuis l\'environnement de production');
    });
```

### Macroable : ajouter des méthodes personnalisées

`macro()` permet à l'application d'ajouter des méthodes à `BlueskyManager`. On les définit typiquement dans la méthode `boot()` d'`AppServiceProvider`.

```php theme={null}
use Revolution\Bluesky\Facades\Bluesky;

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

// Exemple d'utilisation
Bluesky::login(config('bluesky.identifier'), config('bluesky.password'))
    ->postWithHashtag('Hello', 'laravel');
```

## Injecter un Agent personnalisé

`withAgent()` permet d'installer directement une implémentation d'`Agent` de votre choix.

```php theme={null}
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Contracts\Agent;

// Pour implémenter un Agent personnalisé, implémentez l'interface Agent
class MyCustomAgent implements Agent
{
    // ...
}

Bluesky::withAgent(new MyCustomAgent());
```

<Info>
  Comme l'authentification normale (`login()` / `withToken()`) installe automatiquement l'agent, l'usage direct de `withAgent()` intervient surtout lors des tests.
</Info>

## Liens utiles

* [Comparaison des méthodes d'authentification](/fr/packages/laravel-bluesky/authentication) — Détails App Password vs OAuth
* [Client de base](/fr/packages/laravel-bluesky/basic-client) — Exemples d'appels d'API après authentification
* [Tests](/fr/packages/laravel-bluesky/testing) — Méthodes de test avec Fake
* Source : [src/BlueskyManager.php](https://github.com/invokable/laravel-bluesky/blob/main/src/BlueskyManager.php)
* Source : [src/HasShortHand.php](https://github.com/invokable/laravel-bluesky/blob/main/src/HasShortHand.php)


## Related topics

- [Tutoriel bot - Laravel Bluesky](/fr/packages/laravel-bluesky/bot-tutorial.md)
- [Comparaison des méthodes d'authentification - Laravel Bluesky](/fr/packages/laravel-bluesky/authentication.md)
- [Laravel Bluesky](/fr/packages/laravel-bluesky/index.md)
- [Illuminate\Support\Manager — anatomie du système de drivers](/fr/advanced/manager.md)
- [Socialite - Laravel Bluesky](/fr/packages/laravel-bluesky/socialite.md)
