Zum Hauptinhalt springen
Core ist eine tiefgehende interne Implementierung. Für normale Posts, Feed-Abrufe oder Benachrichtigungen wird es nicht benötigt. Ziehen Sie es heran, wenn Sie die Datenstrukturen des AT Protocols direkt manipulieren.

Überblick über das Datenmodell des AT Protocols

Repositorys des AT Protocols nutzen eine content-adressierte Datenstruktur. Für Speicherung, Übertragung und Verifizierung werden folgende Bausteine verwendet.
KlasseRolle
CBORBinäre Serialisierung
CIDContent-Adressierung (Hash-Identifier)
CARLesen/Schreiben von Repository-Archiven
TIDZeitbasierter Record-Key
VarintVariable-Length-Integer-Encoding (intern)

CBOR

Die Klasse CBOR bietet Encoding/Decoding im DAG-CBOR-Format, das das AT Protocol verwendet. Als Erweiterung des Standard-CBOR unterstützt es CID-Links (Tag 42).

Encoding

use Revolution\Bluesky\Core\CBOR;

$record = [
    '$type'     => 'app.bsky.feed.post',
    'text'      => 'Hello, Bluesky!',
    'createdAt' => '2025-01-01T00:00:00.000Z',
];

$bytes = CBOR::encode($record); // Binärer String

Decoding

use Revolution\Bluesky\Core\CBOR;

// Ein einzelnes Item decodieren
$data = CBOR::decode($bytes);

// Das erste Item eines Streams decodieren und den Rest zurückgeben
[$item, $remainder] = CBOR::decodeFirst($bytes);

// Alle Items eines Streams decodieren
$items = CBOR::decodeAll($bytes);

Anwendungsfall

Wenn Sie die CID eines Posts manuell berechnen oder verifizieren möchten, wird CBOR-Encoding benötigt (siehe auch verify-Seite).
use Revolution\Bluesky\Core\CBOR;
use Revolution\Bluesky\Core\CID;

$record = data_get($block, 'value');
$cbor   = CBOR::encode($record);
$bool   = CID::verify($cbor, data_get($block, 'cid'));

CID (Content Identifier)

Eine CID ist ein selbstbeschreibender Identifier auf Basis des Daten-Hashs. Das AT Protocol wickelt einen SHA-256-Hash in Multihash und codiert ihn zusätzlich mit Multicodec und Multibase.

CIDv0 und CIDv1

VersionEncodingAnfangszeichenVerwendung
v0base58btcQm...Alte Spezifikation (Blobs)
v1base32bafy...Neue Spezifikation (Records)

Wichtige API

use Revolution\Bluesky\Core\CID;

// CID aus Daten erzeugen
$cid = CID::encode($data, CID::DAG_CBOR); // für Records
$cid = CID::encode($data, CID::RAW);      // Binärdaten (z. B. Bilder)

// CID verifizieren
$bool = CID::verify($data, $cid, CID::DAG_CBOR);
$bool = CID::verify($file, $cid, CID::RAW);

// CID zerlegen
$decoded = CID::decode($cid); // ['version', 'codec', 'hash']

// CID-Version prüfen
$version = CID::version($cid); // 0 oder 1

// Umwandlung in Byte-Repräsentation
$bytes = CID::decodeBytes($cid);
$cid   = CID::encodeBytes($bytes);

CAR (Content Addressable aRchive)

Eine CAR-Datei ist ein Binärformat, das AT-Protocol-Repositorys als Folge von Blöcken speichert. Die über com.atproto.sync.getRepo abgerufenen Daten liegen in diesem Format vor.

Decoding

use Revolution\Bluesky\Core\CAR;

// Gesamte CAR-Datei decodieren (Root und alle Blöcke)
['roots' => $roots, 'blocks' => $blocks] = CAR::decode($carData);

// Nur die Root-CIDs abrufen
$roots = CAR::decodeRoots($carData);

// Über Blöcke iterieren
foreach (CAR::blockIterator($carData) as [$cid, $block]) {
    // $cid: CID-String, $block: Binärdaten
}

// Als Record-Map abrufen
foreach (CAR::blockMap($carData) as $key => $record) {
    // $key: Record-Key, $record: bereits decodiertes Array
}

Signed Commit verifizieren

Um zu prüfen, ob eine CAR-Datei tatsächlich zu einem bestimmten Nutzer gehört, wird die Signatur des Signed Commit mit dem öffentlichen Schlüssel aus dem DID-Document verifiziert.
use Revolution\Bluesky\Core\CAR;
use Revolution\Bluesky\Crypto\DidKey;
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Support\DidDocument;

$did = 'did:plc:***';

$didDoc    = DidDocument::make(Bluesky::identity()->resolveDID($did)->json());
$publicKey = DidKey::parse($didDoc->publicKey());

$signed    = CAR::signedCommit($carData);
$bool      = CAR::verifySignedCommit($signed, $publicKey);
Beispielimplementierung: DownloadRepoCommand

TID (Timestamp Identifier)

TID ist eine zeitbasierte ID, die als Record-Key im AT Protocol verwendet wird. Sie kombiniert einen Mikrosekunden-Zeitstempel und eine Clock-ID zu einem 13-stelligen base32-encodierten String.
Beispiel: 3jujm55ngfc24

Erzeugen und Umwandeln

use Revolution\Bluesky\Core\TID;

// Die nächste TID erzeugen
$tid = TID::next();
echo $tid->toString(); // String wie "3jujm55ngfc24"

// TID aus einem String erstellen
$tid = TID::fromStr('3jujm55ngfc24');

// Aus Zeitstempel (Mikrosekunden) und Clock-ID erstellen
$tid = TID::fromTime(microtime(true) * 1000000, 0);

Aufbau einer TID

Mit TID::s32encode() und TID::s32decode() können Sie zwischen Integer und String hin- und herwandeln.

Varint (Variable-Length-Integer)

Varint ist ein internes Utility für die Binäranalyse von CAR/CBOR. Es wird normalerweise nicht direkt verwendet.
use Revolution\Bluesky\Core\Varint;

// Integer encodieren
$bytes = Varint::encode(1234);

// Aus einem Stream decodieren (Wert und verbrauchte Bytes zurückgeben)
[$value, $bytesRead] = Varint::decodeStream($stream);

Zum Mocken der Core-Funktionen

Da die Core-Funktionen (CBOR/CID/CAR/TID) keine externen Zugriffe durchführen, müssen sie in Tests nicht gemockt werden.
// Auch in Tests direkt verwendbar
$bytes = CBOR::encode(['text' => 'Hello']);
$cid   = CID::encode($bytes, CID::DAG_CBOR);
$bool  = CID::verify($bytes, $cid);

Source: src/Core/
Zuletzt geändert am 13. Juli 2026