Laravel AT Protocol Client (alpha & unstable)
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'refs/heads/dev'

+331
+2
src/AtpClient.php
··· 7 7 use SocialDept\AtpClient\Client\ChatClient; 8 8 use SocialDept\AtpClient\Client\Client; 9 9 use SocialDept\AtpClient\Client\OzoneClient; 10 + use SocialDept\AtpClient\Concerns\HasExtensions; 10 11 use SocialDept\AtpClient\Session\SessionManager; 11 12 12 13 class AtpClient 13 14 { 15 + use HasExtensions; 14 16 /** 15 17 * Raw API communication/networking class 16 18 */
+12
src/Client/AtprotoClient.php
··· 4 4 5 5 use SocialDept\AtpClient\AtpClient; 6 6 use SocialDept\AtpClient\Client\Requests\Atproto; 7 + use SocialDept\AtpClient\Concerns\HasDomainExtensions; 7 8 8 9 class AtprotoClient 9 10 { 11 + use HasDomainExtensions; 10 12 /** 11 13 * The parent AtpClient instance 12 14 */ ··· 39 41 $this->server = new Atproto\ServerRequestClient($this); 40 42 $this->identity = new Atproto\IdentityRequestClient($this); 41 43 $this->sync = new Atproto\SyncRequestClient($this); 44 + } 45 + 46 + protected function getDomainName(): string 47 + { 48 + return 'atproto'; 49 + } 50 + 51 + protected function getRootClientClass(): string 52 + { 53 + return AtpClient::class; 42 54 } 43 55 }
+12
src/Client/BskyClient.php
··· 8 8 use SocialDept\AtpClient\Client\Records\PostRecordClient; 9 9 use SocialDept\AtpClient\Client\Records\ProfileRecordClient; 10 10 use SocialDept\AtpClient\Client\Requests\Bsky; 11 + use SocialDept\AtpClient\Concerns\HasDomainExtensions; 11 12 12 13 class BskyClient 13 14 { 15 + use HasDomainExtensions; 14 16 /** 15 17 * The parent AtpClient instance 16 18 */ ··· 55 57 $this->profile = new ProfileRecordClient($this); 56 58 $this->like = new LikeRecordClient($this); 57 59 $this->follow = new FollowRecordClient($this); 60 + } 61 + 62 + protected function getDomainName(): string 63 + { 64 + return 'bsky'; 65 + } 66 + 67 + protected function getRootClientClass(): string 68 + { 69 + return AtpClient::class; 58 70 } 59 71 }
+12
src/Client/ChatClient.php
··· 4 4 5 5 use SocialDept\AtpClient\AtpClient; 6 6 use SocialDept\AtpClient\Client\Requests\Chat; 7 + use SocialDept\AtpClient\Concerns\HasDomainExtensions; 7 8 8 9 class ChatClient 9 10 { 11 + use HasDomainExtensions; 10 12 /** 11 13 * The parent AtpClient instance 12 14 */ ··· 27 29 $this->atp = $parent; 28 30 $this->convo = new Chat\ConvoRequestClient($this); 29 31 $this->actor = new Chat\ActorRequestClient($this); 32 + } 33 + 34 + protected function getDomainName(): string 35 + { 36 + return 'chat'; 37 + } 38 + 39 + protected function getRootClientClass(): string 40 + { 41 + return AtpClient::class; 30 42 } 31 43 }
+12
src/Client/OzoneClient.php
··· 4 4 5 5 use SocialDept\AtpClient\AtpClient; 6 6 use SocialDept\AtpClient\Client\Requests\Ozone; 7 + use SocialDept\AtpClient\Concerns\HasDomainExtensions; 7 8 8 9 class OzoneClient 9 10 { 11 + use HasDomainExtensions; 10 12 /** 11 13 * The parent AtpClient instance 12 14 */ ··· 33 35 $this->moderation = new Ozone\ModerationRequestClient($this); 34 36 $this->server = new Ozone\ServerRequestClient($this); 35 37 $this->team = new Ozone\TeamRequestClient($this); 38 + } 39 + 40 + protected function getDomainName(): string 41 + { 42 + return 'ozone'; 43 + } 44 + 45 + protected function getRootClientClass(): string 46 + { 47 + return AtpClient::class; 36 48 } 37 49 }
+3
src/Client/Public/AtpPublicClient.php
··· 2 2 3 3 namespace SocialDept\AtpClient\Client\Public; 4 4 5 + use SocialDept\AtpClient\Concerns\HasExtensions; 6 + 5 7 class AtpPublicClient 6 8 { 9 + use HasExtensions; 7 10 public PublicClient $client; 8 11 public BskyPublicClient $bsky; 9 12 public AtprotoPublicClient $atproto;
+16
src/Client/Public/AtprotoPublicClient.php
··· 3 3 namespace SocialDept\AtpClient\Client\Public; 4 4 5 5 use SocialDept\AtpClient\Client\Public\Requests\Atproto\IdentityPublicRequestClient; 6 + use SocialDept\AtpClient\Client\Public\Requests\Atproto\RepoPublicRequestClient; 7 + use SocialDept\AtpClient\Concerns\HasDomainExtensions; 6 8 7 9 class AtprotoPublicClient 8 10 { 11 + use HasDomainExtensions; 12 + 9 13 public AtpPublicClient $atp; 10 14 public IdentityPublicRequestClient $identity; 15 + public RepoPublicRequestClient $repo; 11 16 12 17 public function __construct(AtpPublicClient $parent) 13 18 { 14 19 $this->atp = $parent; 15 20 $this->identity = new IdentityPublicRequestClient($this); 21 + $this->repo = new RepoPublicRequestClient($this); 22 + } 23 + 24 + protected function getDomainName(): string 25 + { 26 + return 'atproto'; 27 + } 28 + 29 + protected function getRootClientClass(): string 30 + { 31 + return AtpPublicClient::class; 16 32 } 17 33 }
+13
src/Client/Public/BskyPublicClient.php
··· 6 6 use SocialDept\AtpClient\Client\Public\Requests\Bsky\FeedPublicRequestClient; 7 7 use SocialDept\AtpClient\Client\Public\Requests\Bsky\GraphPublicRequestClient; 8 8 use SocialDept\AtpClient\Client\Public\Requests\Bsky\LabelerPublicRequestClient; 9 + use SocialDept\AtpClient\Concerns\HasDomainExtensions; 9 10 10 11 class BskyPublicClient 11 12 { 13 + use HasDomainExtensions; 14 + 12 15 public AtpPublicClient $atp; 13 16 public ActorPublicRequestClient $actor; 14 17 public FeedPublicRequestClient $feed; ··· 22 25 $this->feed = new FeedPublicRequestClient($this); 23 26 $this->graph = new GraphPublicRequestClient($this); 24 27 $this->labeler = new LabelerPublicRequestClient($this); 28 + } 29 + 30 + protected function getDomainName(): string 31 + { 32 + return 'bsky'; 33 + } 34 + 35 + protected function getRootClientClass(): string 36 + { 37 + return AtpPublicClient::class; 25 38 } 26 39 }
+65
src/Client/Public/Requests/Atproto/RepoPublicRequestClient.php
··· 1 + <?php 2 + 3 + namespace SocialDept\AtpClient\Client\Public\Requests\Atproto; 4 + 5 + use SocialDept\AtpClient\Client\Public\Requests\PublicRequest; 6 + use SocialDept\AtpClient\Data\Responses\Atproto\Repo\DescribeRepoResponse; 7 + use SocialDept\AtpClient\Data\Responses\Atproto\Repo\GetRecordResponse; 8 + use SocialDept\AtpClient\Data\Responses\Atproto\Repo\ListRecordsResponse; 9 + 10 + class RepoPublicRequestClient extends PublicRequest 11 + { 12 + /** 13 + * Get a record 14 + * 15 + * @see https://docs.bsky.app/docs/api/com-atproto-repo-get-record 16 + */ 17 + public function getRecord( 18 + string $repo, 19 + string $collection, 20 + string $rkey, 21 + ?string $cid = null 22 + ): GetRecordResponse { 23 + $response = $this->atp->client->get( 24 + 'com.atproto.repo.getRecord', 25 + compact('repo', 'collection', 'rkey', 'cid') 26 + ); 27 + 28 + return GetRecordResponse::fromArray($response->json()); 29 + } 30 + 31 + /** 32 + * List records in a collection 33 + * 34 + * @see https://docs.bsky.app/docs/api/com-atproto-repo-list-records 35 + */ 36 + public function listRecords( 37 + string $repo, 38 + string $collection, 39 + int $limit = 50, 40 + ?string $cursor = null, 41 + bool $reverse = false 42 + ): ListRecordsResponse { 43 + $response = $this->atp->client->get( 44 + 'com.atproto.repo.listRecords', 45 + compact('repo', 'collection', 'limit', 'cursor', 'reverse') 46 + ); 47 + 48 + return ListRecordsResponse::fromArray($response->json()); 49 + } 50 + 51 + /** 52 + * Describe the repository 53 + * 54 + * @see https://docs.bsky.app/docs/api/com-atproto-repo-describe-repo 55 + */ 56 + public function describeRepo(string $repo): DescribeRepoResponse 57 + { 58 + $response = $this->atp->client->get( 59 + 'com.atproto.repo.describeRepo', 60 + compact('repo') 61 + ); 62 + 63 + return DescribeRepoResponse::fromArray($response->json()); 64 + } 65 + }
+71
src/Concerns/HasDomainExtensions.php
··· 1 + <?php 2 + 3 + namespace SocialDept\AtpClient\Concerns; 4 + 5 + use BadMethodCallException; 6 + 7 + trait HasDomainExtensions 8 + { 9 + /** 10 + * Resolved domain extension instances. 11 + * 12 + * @var array<string, object> 13 + */ 14 + protected array $resolvedDomainExtensions = []; 15 + 16 + /** 17 + * Get the domain name for this client. 18 + */ 19 + abstract protected function getDomainName(): string; 20 + 21 + /** 22 + * Get the root client class for extension lookup. 23 + */ 24 + abstract protected function getRootClientClass(): string; 25 + 26 + /** 27 + * Resolve a domain extension instance. 28 + */ 29 + protected function resolveDomainExtension(string $name): object 30 + { 31 + if (! isset($this->resolvedDomainExtensions[$name])) { 32 + $rootClass = $this->getRootClientClass(); 33 + $extensions = $rootClass::getDomainExtensionsFor($this->getDomainName()); 34 + $this->resolvedDomainExtensions[$name] = ($extensions[$name])($this); 35 + } 36 + 37 + return $this->resolvedDomainExtensions[$name]; 38 + } 39 + 40 + /** 41 + * Check if a domain extension exists. 42 + */ 43 + protected function hasDomainExtension(string $name): bool 44 + { 45 + $rootClass = $this->getRootClientClass(); 46 + 47 + return $rootClass::hasDomainExtension($this->getDomainName(), $name); 48 + } 49 + 50 + /** 51 + * Magic getter for domain extension access. 52 + */ 53 + public function __get(string $name): mixed 54 + { 55 + if ($this->hasDomainExtension($name)) { 56 + return $this->resolveDomainExtension($name); 57 + } 58 + 59 + throw new BadMethodCallException( 60 + sprintf('Property [%s] does not exist on [%s].', $name, static::class) 61 + ); 62 + } 63 + 64 + /** 65 + * Magic isset for domain extension checking. 66 + */ 67 + public function __isset(string $name): bool 68 + { 69 + return $this->hasDomainExtension($name); 70 + } 71 + }
+113
src/Concerns/HasExtensions.php
··· 1 + <?php 2 + 3 + namespace SocialDept\AtpClient\Concerns; 4 + 5 + use BadMethodCallException; 6 + use Closure; 7 + 8 + trait HasExtensions 9 + { 10 + /** 11 + * Registered domain client extensions. 12 + * 13 + * @var array<string, Closure> 14 + */ 15 + protected static array $extensions = []; 16 + 17 + /** 18 + * Registered request client extensions for existing domains. 19 + * 20 + * @var array<string, array<string, Closure>> 21 + */ 22 + protected static array $domainExtensions = []; 23 + 24 + /** 25 + * Resolved extension instances (lazy loading). 26 + * 27 + * @var array<string, object> 28 + */ 29 + protected array $resolvedExtensions = []; 30 + 31 + /** 32 + * Register a domain client extension. 33 + */ 34 + public static function extend(string $name, Closure $callback): void 35 + { 36 + static::$extensions[$name] = $callback; 37 + } 38 + 39 + /** 40 + * Register a request client extension for an existing domain. 41 + */ 42 + public static function extendDomain(string $domain, string $name, Closure $callback): void 43 + { 44 + static::$domainExtensions[$domain][$name] = $callback; 45 + } 46 + 47 + /** 48 + * Check if an extension is registered. 49 + */ 50 + public static function hasExtension(string $name): bool 51 + { 52 + return isset(static::$extensions[$name]); 53 + } 54 + 55 + /** 56 + * Check if a domain extension is registered. 57 + */ 58 + public static function hasDomainExtension(string $domain, string $name): bool 59 + { 60 + return isset(static::$domainExtensions[$domain][$name]); 61 + } 62 + 63 + /** 64 + * Get domain extensions for a specific domain. 65 + */ 66 + public static function getDomainExtensionsFor(string $domain): array 67 + { 68 + return static::$domainExtensions[$domain] ?? []; 69 + } 70 + 71 + /** 72 + * Flush all registered extensions (useful for testing). 73 + */ 74 + public static function flushExtensions(): void 75 + { 76 + static::$extensions = []; 77 + static::$domainExtensions = []; 78 + } 79 + 80 + /** 81 + * Resolve an extension instance. 82 + */ 83 + protected function resolveExtension(string $name): object 84 + { 85 + if (! isset($this->resolvedExtensions[$name])) { 86 + $this->resolvedExtensions[$name] = (static::$extensions[$name])($this); 87 + } 88 + 89 + return $this->resolvedExtensions[$name]; 90 + } 91 + 92 + /** 93 + * Magic getter for extension access. 94 + */ 95 + public function __get(string $name): mixed 96 + { 97 + if (static::hasExtension($name)) { 98 + return $this->resolveExtension($name); 99 + } 100 + 101 + throw new BadMethodCallException( 102 + sprintf('Property [%s] does not exist on [%s].', $name, static::class) 103 + ); 104 + } 105 + 106 + /** 107 + * Magic isset for extension checking. 108 + */ 109 + public function __isset(string $name): bool 110 + { 111 + return static::hasExtension($name); 112 + } 113 + }