Laravel AT Protocol Client (alpha & unstable)
at dev 2.4 kB view raw
1<?php 2 3namespace SocialDept\AtpClient\Attributes; 4 5use Attribute; 6use SocialDept\AtpClient\Enums\Scope; 7 8/** 9 * Documents that a method requires authentication with specific OAuth scopes. 10 * 11 * This attribute currently serves as documentation to indicate which AT Protocol 12 * endpoints require authentication and what scopes they need. It helps developers 13 * understand scope requirements when building applications. 14 * 15 * While this attribute does not currently perform runtime enforcement, scope 16 * validation will be implemented in a future release. Correctly attributing 17 * endpoints now ensures forward compatibility when enforcement is enabled. 18 * 19 * The AT Protocol currently uses "transition scopes" (like `transition:generic`) while 20 * moving toward more granular scopes. The `granular` parameter allows documenting the 21 * future granular scope that will replace the transition scope. 22 * 23 * @example Basic usage with a transition scope 24 * ```php 25 * #[ScopedEndpoint(Scope::TransitionGeneric)] 26 * public function getTimeline(): GetTimelineResponse 27 * ``` 28 * 29 * @example With future granular scope documented 30 * ```php 31 * #[ScopedEndpoint(Scope::TransitionGeneric, granular: 'rpc:app.bsky.feed.getTimeline')] 32 * public function getTimeline(): GetTimelineResponse 33 * ``` 34 * 35 * @see \SocialDept\AtpClient\Attributes\PublicEndpoint For endpoints that don't require authentication 36 * @see \SocialDept\AtpClient\Enums\Scope For available scope values 37 */ 38#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] 39class ScopedEndpoint 40{ 41 public array $scopes; 42 43 /** 44 * @param string|Scope|array<string|Scope> $scopes Required scope(s) for this method 45 * @param string|null $granular Future granular scope equivalent 46 * @param string $description Human-readable description of scope requirement 47 */ 48 public function __construct( 49 string|Scope|array $scopes, 50 public readonly ?string $granular = null, 51 public readonly string $description = '', 52 ) { 53 $this->scopes = $this->normalizeScopes($scopes); 54 } 55 56 protected function normalizeScopes(string|Scope|array $scopes): array 57 { 58 if (! is_array($scopes)) { 59 $scopes = [$scopes]; 60 } 61 62 return array_map( 63 fn ($scope) => $scope instanceof Scope ? $scope->value : $scope, 64 $scopes 65 ); 66 } 67}