+43
src/Attributes/PublicEndpoint.php
+43
src/Attributes/PublicEndpoint.php
···
1
+
<?php
2
+
3
+
namespace SocialDept\AtpClient\Attributes;
4
+
5
+
use Attribute;
6
+
7
+
/**
8
+
* Documents that a method is a public endpoint that does not require authentication.
9
+
*
10
+
* This attribute currently serves as documentation to indicate which AT Protocol
11
+
* endpoints can be called without an authenticated session. It helps developers
12
+
* understand which endpoints work with `Atp::public()` against public API endpoints
13
+
* like `https://public.api.bsky.app`.
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
+
* Public endpoints typically include operations like:
20
+
* - Reading public profiles and posts
21
+
* - Searching actors and content
22
+
* - Resolving handles to DIDs
23
+
* - Accessing repository data (sync endpoints)
24
+
* - Describing servers and feed generators
25
+
*
26
+
* @example Basic usage
27
+
* ```php
28
+
* #[PublicEndpoint]
29
+
* public function getProfile(string $actor): ProfileViewDetailed
30
+
* ```
31
+
*
32
+
* @see \SocialDept\AtpClient\Attributes\ScopedEndpoint For endpoints that require authentication
33
+
*/
34
+
#[Attribute(Attribute::TARGET_METHOD)]
35
+
class PublicEndpoint
36
+
{
37
+
/**
38
+
* @param string $description Human-readable description of the endpoint
39
+
*/
40
+
public function __construct(
41
+
public readonly string $description = '',
42
+
) {}
43
+
}
+67
src/Attributes/ScopedEndpoint.php
+67
src/Attributes/ScopedEndpoint.php
···
1
+
<?php
2
+
3
+
namespace SocialDept\AtpClient\Attributes;
4
+
5
+
use Attribute;
6
+
use 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)]
39
+
class 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
+
}