Resolve AT Protocol DIDs, handles, and schemas with intelligent caching for Laravel
at main 4.9 kB view raw
1<?php 2 3namespace SocialDept\AtpResolver; 4 5use SocialDept\AtpResolver\Contracts\CacheStore; 6use SocialDept\AtpResolver\Contracts\DidResolver; 7use SocialDept\AtpResolver\Contracts\HandleResolver; 8use SocialDept\AtpResolver\Data\DidDocument; 9use SocialDept\AtpResolver\Exceptions\DidResolutionException; 10use SocialDept\AtpResolver\Exceptions\HandleResolutionException; 11use SocialDept\AtpResolver\Support\Concerns\HasConfig; 12use SocialDept\AtpResolver\Support\Identity; 13 14class Resolver 15{ 16 use HasConfig; 17 18 /** 19 * Create a new Resolver instance. 20 */ 21 public function __construct( 22 protected DidResolver $didResolver, 23 protected HandleResolver $handleResolver, 24 protected CacheStore $cache 25 ) { 26 } 27 28 /** 29 * Resolve a DID to a DID Document. 30 * 31 * @param string $did 32 * @param bool $useCache 33 * @return DidDocument 34 * @throws DidResolutionException 35 */ 36 public function resolveDid(string $did, bool $useCache = true): DidDocument 37 { 38 $cacheKey = "did:{$did}"; 39 40 if ($useCache && $this->cache->has($cacheKey)) { 41 $cached = $this->cache->get($cacheKey); 42 43 if ($cached instanceof DidDocument) { 44 return $cached; 45 } 46 } 47 48 $document = $this->didResolver->resolve($did); 49 50 if ($useCache) { 51 $ttl = $this->getConfig('resolver.cache.did_ttl', 3600); 52 $this->cache->put($cacheKey, $document, $ttl); 53 } 54 55 return $document; 56 } 57 58 /** 59 * Convert a handle to its DID. 60 * 61 * @param string $handle 62 * @param bool $useCache 63 * @return string 64 * @throws HandleResolutionException 65 */ 66 public function handleToDid(string $handle, bool $useCache = true): string 67 { 68 $cacheKey = "handle:{$handle}"; 69 70 if ($useCache && $this->cache->has($cacheKey)) { 71 return $this->cache->get($cacheKey); 72 } 73 74 $did = $this->handleResolver->resolve($handle); 75 76 if ($useCache) { 77 $ttl = $this->getConfig('resolver.cache.handle_ttl', 3600); 78 $this->cache->put($cacheKey, $did, $ttl); 79 } 80 81 return $did; 82 } 83 84 /** 85 * Resolve a handle to its DID Document. 86 * 87 * @param string $handle 88 * @param bool $useCache 89 * @return DidDocument 90 * @throws DidResolutionException 91 * @throws HandleResolutionException 92 */ 93 public function resolveHandle(string $handle, bool $useCache = true): DidDocument 94 { 95 $did = $this->handleToDid($handle, $useCache); 96 97 return $this->resolveDid($did, $useCache); 98 } 99 100 /** 101 * Resolve an identity (DID or handle) to its DID Document. 102 * 103 * @param string $actor A DID or handle 104 * @param bool $useCache 105 * @return DidDocument 106 * @throws DidResolutionException 107 * @throws HandleResolutionException 108 */ 109 public function resolveIdentity(string $actor, bool $useCache = true): DidDocument 110 { 111 return Identity::isDid($actor) 112 ? $this->resolveDid($actor, $useCache) 113 : $this->resolveHandle($actor, $useCache); 114 } 115 116 /** 117 * Clear cached data for a DID. 118 * 119 * @param string $did 120 */ 121 public function clearDidCache(string $did): void 122 { 123 $this->cache->forget("did:{$did}"); 124 } 125 126 /** 127 * Clear cached data for a handle. 128 * 129 * @param string $handle 130 */ 131 public function clearHandleCache(string $handle): void 132 { 133 $this->cache->forget("handle:{$handle}"); 134 } 135 136 /** 137 * Clear all cached data. 138 */ 139 public function clearCache(): void 140 { 141 $this->cache->flush(); 142 } 143 144 /** 145 * Resolve a DID or handle to its PDS endpoint. 146 * 147 * @param string $actor A DID (e.g., "did:plc:abc123") or handle (e.g., "user.bsky.social") 148 * @param bool $useCache 149 * @return string|null The PDS endpoint URL or null if not found 150 * @throws DidResolutionException 151 * @throws HandleResolutionException 152 */ 153 public function resolvePds(string $actor, bool $useCache = true): ?string 154 { 155 $cacheKey = "pds:{$actor}"; 156 157 if ($useCache && $this->cache->has($cacheKey)) { 158 return $this->cache->get($cacheKey); 159 } 160 161 // Determine if input is a DID or handle 162 $document = $this->resolveIdentity($actor, $useCache); 163 164 $pdsEndpoint = $document->getPdsEndpoint(); 165 166 if ($useCache && $pdsEndpoint !== null) { 167 $ttl = $this->getConfig('resolver.cache.pds_ttl', 3600); 168 $this->cache->put($cacheKey, $pdsEndpoint, $ttl); 169 } 170 171 return $pdsEndpoint; 172 } 173 174 /** 175 * Clear cached PDS endpoint for a DID or handle. 176 * 177 * @param string $actor 178 */ 179 public function clearPdsCache(string $actor): void 180 { 181 $this->cache->forget("pds:{$actor}"); 182 } 183}