Resolve AT Protocol DIDs, handles, and schemas with intelligent caching for Laravel
at main 2.3 kB view raw
1<?php 2 3namespace SocialDept\AtpResolver\Resolvers; 4 5use GuzzleHttp\Client; 6use GuzzleHttp\Exception\GuzzleException; 7use SocialDept\AtpResolver\Contracts\HandleResolver; 8use SocialDept\AtpResolver\Exceptions\HandleResolutionException; 9use SocialDept\AtpResolver\Support\Concerns\HasConfig; 10 11class AtProtoHandleResolver implements HandleResolver 12{ 13 use HasConfig; 14 15 protected Client $client; 16 17 protected string $pdsEndpoint; 18 19 /** 20 * Create a new AT Protocol handle resolver instance. 21 * 22 * @param string|null $pdsEndpoint The PDS endpoint to use for resolution 23 */ 24 public function __construct(?string $pdsEndpoint = null, ?int $timeout = null) 25 { 26 $this->pdsEndpoint = $pdsEndpoint ?? $this->getConfig('resolver.pds_endpoint', 'https://bsky.social'); 27 $this->client = new Client([ 28 'timeout' => $timeout ?? $this->getConfig('resolver.timeout', 10), 29 'headers' => [ 30 'Accept' => 'application/json', 31 'User-Agent' => 'Beacon/1.0', 32 ], 33 ]); 34 } 35 36 /** 37 * Resolve a handle to a DID. 38 * 39 * @param string $handle The handle to resolve (e.g., "user.bsky.social") 40 * @return string The resolved DID 41 */ 42 public function resolve(string $handle): string 43 { 44 $this->validateHandle($handle); 45 46 try { 47 $response = $this->client->get("{$this->pdsEndpoint}/xrpc/com.atproto.identity.resolveHandle", [ 48 'query' => ['handle' => $handle], 49 ]); 50 51 $data = json_decode($response->getBody()->getContents(), true); 52 53 if (! isset($data['did'])) { 54 throw HandleResolutionException::resolutionFailed($handle, 'No DID in response'); 55 } 56 57 return $data['did']; 58 } catch (GuzzleException $e) { 59 throw HandleResolutionException::resolutionFailed($handle, $e->getMessage()); 60 } 61 } 62 63 /** 64 * Validate a handle format. 65 * 66 * @param string $handle 67 */ 68 protected function validateHandle(string $handle): void 69 { 70 // Handle must be a valid domain name 71 if (! preg_match('/^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/', $handle)) { 72 throw HandleResolutionException::invalidFormat($handle); 73 } 74 } 75}