> ## 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 en HasShortHand

> Uitleg over de architectuur van BlueskyManager, de implementatie achter de Bluesky Facade, en de shortcutmethodes die de HasShortHand-trait biedt.

## Overzicht

De `Bluesky` Facade is een dunne wrapper rond `BlueskyManager`. `BlueskyManager` beheert meerdere Agents, en de `HasShortHand`-trait biedt een verzameling shortcuts voor veelgebruikte methodes.

## Architectuur

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

`BlueskyServiceProvider` registreert `Factory::class` als `BlueskyManager` via een scoped singleton (één instantie per request).

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

De `getFacadeAccessor()` van de Facade lost deze binding op.

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

## Kernmethodes van BlueskyManager

Dit zijn de kernmethodes die `BlueskyManager` zelf definieert. Het helpt bij het begrijpen van de interne structuur om deze te onderscheiden van de methodes uit de `HasShortHand`-trait.

### Authenticatie

| Methode                                                                | Beschrijving                                                               |
| ---------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `login(string $identifier, string $password, ?string $service = null)` | Authenticeert met App Password en stelt een `LegacyAgent` in               |
| `withToken(?AbstractSession $token)`                                   | Stelt een Agent in op basis van een `OAuthSession` of `LegacySession`      |
| `check(): bool`                                                        | Controleert of je geauthenticeerd bent (valideert ook de tokenvervaldatum) |
| `refreshSession()`                                                     | Vernieuwt de token                                                         |
| `logout()`                                                             | Wist de Agent                                                              |

### Agent-operaties

| Methode                    | Beschrijving                                                                              |
| -------------------------- | ----------------------------------------------------------------------------------------- |
| `agent(): ?Agent`          | Haalt de huidige Agent op                                                                 |
| `withAgent(?Agent $agent)` | Stelt een Agent direct in                                                                 |
| `assertDid(): string`      | Geeft de geauthenticeerde DID terug. Gooit een exception als je niet geauthenticeerd bent |

### HTTP-client

| Methode                                                                                          | Beschrijving                                                        |
| ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
| `client(bool $auth = true): AtpClient`                                                           | Geeft een geauthenticeerde (of anonieme) XRPC-client terug          |
| `public(): BskyClient`                                                                           | Geeft een client terug voor publieke endpoints zonder authenticatie |
| `send(BackedEnum\|string $api, string $method, bool $auth, ?array $params, ?callable $callback)` | Roept een willekeurige AT Protocol API direct aan                   |

### Utilities

| Methode                           | Beschrijving                                                  |
| --------------------------------- | ------------------------------------------------------------- |
| `identity(): Identity`            | Haalt de identity-service op, voor onder andere DID-resolutie |
| `pds(): PDS`                      | Haalt de PDS-informatieservice op                             |
| `entryway(?string $path): string` | Geeft de service-URL terug (zoals `bsky.social`)              |
| `publicEndpoint(): string`        | Geeft de publieke endpoint-URL terug                          |

## De HasShortHand-trait

De `HasShortHand`-trait verpakt de low-level API's van het AT Protocol in duidelijke, PHP-vriendelijke methodes. Door simpelweg `use HasShortHand;` toe te voegen aan `BlueskyManager` kun je deze methodes direct via `Bluesky::` aanroepen.

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

<Info>
  De reden dat `HasShortHand` een aparte trait is, is dat dit het testen en aanpassen makkelijker maakt. Met deze trait blijft de code van `BlueskyManager` eenvoudig, terwijl er toch een rijke set API-shortcuts beschikbaar is.
</Info>

### Posts en feeds

| Methode                                                         | Beschrijving                               |
| --------------------------------------------------------------- | ------------------------------------------ |
| `post(Post\|string\|array $text)`                               | Maakt een nieuwe post                      |
| `getPost(string $uri)`                                          | Haalt een post op via AT-URI               |
| `getPosts(array $uris)`                                         | Haalt meerdere posts in één keer op        |
| `deletePost(string $uri)`                                       | Verwijdert een post                        |
| `getTimeline(?string $algorithm, ?int $limit, ?string $cursor)` | Haalt de home-timeline op                  |
| `getAuthorFeed(?string $actor, ...)`                            | Haalt de feed van een specifiek account op |
| `searchPosts(string $q, ...)`                                   | Zoekt posts                                |

### Interacties

| Methode                              | Beschrijving                                |
| ------------------------------------ | ------------------------------------------- |
| `like(Like\|StrongRef $subject)`     | Maakt een like                              |
| `deleteLike(string $uri)`            | Verwijdert een like                         |
| `repost(Repost\|StrongRef $subject)` | Maakt een repost                            |
| `deleteRepost(string $uri)`          | Verwijdert een repost                       |
| `getActorLikes(?string $actor, ...)` | Haalt de lijst met likes van een account op |

### Volgen

| Methode                             | Beschrijving                            |
| ----------------------------------- | --------------------------------------- |
| `follow(Follow\|string $did)`       | Volgt een account                       |
| `deleteFollow(string $uri)`         | Ontvolgt een account                    |
| `getFollowers(?string $actor, ...)` | Haalt de lijst met volgers op           |
| `getFollows(?string $actor, ...)`   | Haalt de lijst met gevolgde accounts op |

### Profiel en account

| Methode                             | Beschrijving                    |
| ----------------------------------- | ------------------------------- |
| `getProfile(?string $actor)`        | Haalt een profiel op            |
| `upsertProfile(callable $callback)` | Werkt een profiel bij           |
| `resolveHandle(string $handle)`     | Lost een handle op naar een DID |

### Media

| Methode                                                    | Beschrijving                                  |
| ---------------------------------------------------------- | --------------------------------------------- |
| `uploadBlob(StreamInterface\|string $data, string $type)`  | Uploadt een blob, zoals een afbeelding        |
| `uploadVideo(StreamInterface\|string $data, string $type)` | Uploadt een video                             |
| `getJobStatus(string $jobId)`                              | Controleert de jobstatus van een video-upload |
| `getUploadLimits()`                                        | Haalt de uploadlimieten op                    |

### Notificaties

| Methode                                   | Beschrijving                               |
| ----------------------------------------- | ------------------------------------------ |
| `listNotifications(...)`                  | Haalt de lijst met notificaties op         |
| `countUnreadNotifications(...)`           | Haalt het aantal ongelezen notificaties op |
| `updateSeenNotifications(string $seenAt)` | Markeert notificaties als gelezen          |

### AT Protocol record-operaties

| Methode                                                             | Beschrijving                          |
| ------------------------------------------------------------------- | ------------------------------------- |
| `createRecord(string $repo, string $collection, ...)`               | Maakt een record                      |
| `getRecord(string $repo, string $collection, string $rkey, ...)`    | Haalt een record op                   |
| `listRecords(string $repo, string $collection, ...)`                | Haalt een lijst met records op        |
| `putRecord(string $repo, string $collection, string $rkey, ...)`    | Werkt een record bij of maakt het aan |
| `deleteRecord(string $repo, string $collection, string $rkey, ...)` | Verwijdert een record                 |

### Feedgenerators en labelers

| Methode                                                                | Beschrijving                 |
| ---------------------------------------------------------------------- | ---------------------------- |
| `publishFeedGenerator(BackedEnum\|string $name, Generator $generator)` | Publiceert een feedgenerator |
| `createThreadGate(string $post, ?array $allow)`                        | Maakt een threadgate         |
| `upsertLabelDefinitions(callable $callback)`                           | Werkt labeldefinities bij    |
| `deleteLabelDefinitions()`                                             | Verwijdert labeldefinities   |
| `createLabels(RepoRef\|StrongRef\|array $subject, array $labels)`      | Kent labels toe              |
| `deleteLabels(RepoRef\|StrongRef\|array $subject, array $labels)`      | Verwijdert labels            |

## Voorbeelden van veelgebruikte shortcuts

### Posten

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

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

### Reageren

Voor een reply stel je met `Post::build()` de `StrongRef` van de bovenliggende post in. `HasShortHand` heeft geen aparte `reply()`-methode; je geeft een `Post`-object door aan `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('Tekst van de reply')
    ->reply(root: $parent, parent: $parent);

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

### Liken en reposten

```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...');

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

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

### Profiel bijwerken

`upsertProfile()` haalt het huidige profiel op en slaat de wijzigingen op die je in de closure maakt. Met de methodes van het `Profile`-object kun je onder andere displayName en description instellen.

```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('Nieuwe weergavenaam')
                ->description('Profielbeschrijving');
    });
```

#### Zelflabels instellen

Met `SelfLabels` kun je zelflabels instellen voor het hele account.

```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']));
    });
```

### Een willekeurige API direct aanroepen

Voor methodes die niet in `HasShortHand` zitten, gebruik je `send()` of `client()`.

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

// Een willekeurige XRPC-methode aanroepen met send()
$response = Bluesky::withToken($session)
    ->send(
        api: 'app.bsky.actor.getProfiles',
        method: 'get',
        params: ['actors' => ['did:plc:...', 'did:plc:...']],
    );

// Fijnmaziger werken met client()
$response = Bluesky::withToken($session)
    ->client()
    ->bsky()
    ->getProfiles(actors: ['did:plc:...']);
```

## Verschil tussen de Facade en direct gebruik

`Bluesky::post()` en `app(Factory::class)->post()` werken op dezelfde `BlueskyManager`-instantie.

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

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

// Direct uit de container halen
$manager = app(Factory::class);
$manager->login(config('bluesky.identifier'), config('bluesky.password'))
        ->post('Hello');

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

Door de `scoped`-registratie blijft de sessiestatus na `login()` behouden binnen één request.

## Conditionable en Macroable

`BlueskyManager` gebruikt ook de traits `Conditionable` en `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('Post vanuit de productieomgeving');
    });
```

### Macroable: eigen methodes toevoegen

Met `macro()` kun je vanuit je applicatie methodes toevoegen aan `BlueskyManager`. Meestal definieer je deze in de `boot()` van je `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}");
});

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

## Een custom Agent inpluggen

Met `withAgent()` kun je een willekeurige `Agent`-implementatie direct instellen.

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

// Implementeer de Agent-interface als je een custom Agent maakt
class MyCustomAgent implements Agent
{
    // ...
}

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

<Info>
  Bij de normale authenticatie (`login()` / `withToken()`) wordt de agent automatisch ingesteld, dus `withAgent()` gebruik je in de praktijk vooral bij testen.
</Info>

## Referenties

* [Vergelijking van authenticatiemethodes](/nl/packages/laravel-bluesky/authentication) — details over App Password en OAuth
* [Basic client](/nl/packages/laravel-bluesky/basic-client) — API-voorbeelden na authenticatie
* [Testen](/nl/packages/laravel-bluesky/testing) — testen met Fakes
* 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

- [Bottutorial - Laravel Bluesky](/nl/packages/laravel-bluesky/bot-tutorial.md)
- [Vergelijking van authenticatiemethodes - Laravel Bluesky](/nl/packages/laravel-bluesky/authentication.md)
- [Illuminate\Support\Manager — anatomie van het driversysteem](/nl/advanced/manager.md)
- [Laravel Bluesky](/nl/packages/laravel-bluesky/index.md)
- [Events en listeners](/nl/events.md)
