···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid;
44+55+use SocialDept\AtpClient\Enums\Nsid\Concerns\HasScopeHelpers;
66+77+enum AtprotoIdentity: string
88+{
99+ use HasScopeHelpers;
1010+ case ResolveHandle = 'com.atproto.identity.resolveHandle';
1111+ case UpdateHandle = 'com.atproto.identity.updateHandle';
1212+}
+17
src/Enums/Nsid/AtprotoRepo.php
···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid;
44+55+use SocialDept\AtpClient\Enums\Nsid\Concerns\HasScopeHelpers;
66+77+enum AtprotoRepo: string
88+{
99+ use HasScopeHelpers;
1010+ case CreateRecord = 'com.atproto.repo.createRecord';
1111+ case DeleteRecord = 'com.atproto.repo.deleteRecord';
1212+ case PutRecord = 'com.atproto.repo.putRecord';
1313+ case GetRecord = 'com.atproto.repo.getRecord';
1414+ case ListRecords = 'com.atproto.repo.listRecords';
1515+ case UploadBlob = 'com.atproto.repo.uploadBlob';
1616+ case DescribeRepo = 'com.atproto.repo.describeRepo';
1717+}
+14
src/Enums/Nsid/AtprotoServer.php
···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid;
44+55+use SocialDept\AtpClient\Enums\Nsid\Concerns\HasScopeHelpers;
66+77+enum AtprotoServer: string
88+{
99+ use HasScopeHelpers;
1010+ case CreateSession = 'com.atproto.server.createSession';
1111+ case RefreshSession = 'com.atproto.server.refreshSession';
1212+ case GetSession = 'com.atproto.server.getSession';
1313+ case DescribeServer = 'com.atproto.server.describeServer';
1414+}
+18
src/Enums/Nsid/AtprotoSync.php
···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid;
44+55+use SocialDept\AtpClient\Enums\Nsid\Concerns\HasScopeHelpers;
66+77+enum AtprotoSync: string
88+{
99+ use HasScopeHelpers;
1010+ case GetBlob = 'com.atproto.sync.getBlob';
1111+ case GetRepo = 'com.atproto.sync.getRepo';
1212+ case ListRepos = 'com.atproto.sync.listRepos';
1313+ case GetLatestCommit = 'com.atproto.sync.getLatestCommit';
1414+ case GetRecord = 'com.atproto.sync.getRecord';
1515+ case ListBlobs = 'com.atproto.sync.listBlobs';
1616+ case GetBlocks = 'com.atproto.sync.getBlocks';
1717+ case GetRepoStatus = 'com.atproto.sync.getRepoStatus';
1818+}
+18
src/Enums/Nsid/BskyActor.php
···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid;
44+55+use SocialDept\AtpClient\Enums\Nsid\Concerns\HasScopeHelpers;
66+77+enum BskyActor: string
88+{
99+ use HasScopeHelpers;
1010+ case GetProfile = 'app.bsky.actor.getProfile';
1111+ case GetProfiles = 'app.bsky.actor.getProfiles';
1212+ case GetSuggestions = 'app.bsky.actor.getSuggestions';
1313+ case SearchActors = 'app.bsky.actor.searchActors';
1414+ case SearchActorsTypeahead = 'app.bsky.actor.searchActorsTypeahead';
1515+1616+ // Record type
1717+ case Profile = 'app.bsky.actor.profile';
1818+}
+29
src/Enums/Nsid/BskyFeed.php
···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid;
44+55+use SocialDept\AtpClient\Enums\Nsid\Concerns\HasScopeHelpers;
66+77+enum BskyFeed: string
88+{
99+ use HasScopeHelpers;
1010+ case DescribeFeedGenerator = 'app.bsky.feed.describeFeedGenerator';
1111+ case GetAuthorFeed = 'app.bsky.feed.getAuthorFeed';
1212+ case GetActorFeeds = 'app.bsky.feed.getActorFeeds';
1313+ case GetActorLikes = 'app.bsky.feed.getActorLikes';
1414+ case GetFeed = 'app.bsky.feed.getFeed';
1515+ case GetFeedGenerator = 'app.bsky.feed.getFeedGenerator';
1616+ case GetFeedGenerators = 'app.bsky.feed.getFeedGenerators';
1717+ case GetLikes = 'app.bsky.feed.getLikes';
1818+ case GetPostThread = 'app.bsky.feed.getPostThread';
1919+ case GetPosts = 'app.bsky.feed.getPosts';
2020+ case GetQuotes = 'app.bsky.feed.getQuotes';
2121+ case GetRepostedBy = 'app.bsky.feed.getRepostedBy';
2222+ case GetSuggestedFeeds = 'app.bsky.feed.getSuggestedFeeds';
2323+ case GetTimeline = 'app.bsky.feed.getTimeline';
2424+ case SearchPosts = 'app.bsky.feed.searchPosts';
2525+2626+ // Record types
2727+ case Post = 'app.bsky.feed.post';
2828+ case Like = 'app.bsky.feed.like';
2929+}
+22
src/Enums/Nsid/BskyGraph.php
···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid;
44+55+use SocialDept\AtpClient\Enums\Nsid\Concerns\HasScopeHelpers;
66+77+enum BskyGraph: string
88+{
99+ use HasScopeHelpers;
1010+ case GetFollowers = 'app.bsky.graph.getFollowers';
1111+ case GetFollows = 'app.bsky.graph.getFollows';
1212+ case GetKnownFollowers = 'app.bsky.graph.getKnownFollowers';
1313+ case GetList = 'app.bsky.graph.getList';
1414+ case GetLists = 'app.bsky.graph.getLists';
1515+ case GetRelationships = 'app.bsky.graph.getRelationships';
1616+ case GetStarterPack = 'app.bsky.graph.getStarterPack';
1717+ case GetStarterPacks = 'app.bsky.graph.getStarterPacks';
1818+ case GetSuggestedFollowsByActor = 'app.bsky.graph.getSuggestedFollowsByActor';
1919+2020+ // Record type
2121+ case Follow = 'app.bsky.graph.follow';
2222+}
+11
src/Enums/Nsid/BskyLabeler.php
···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid;
44+55+use SocialDept\AtpClient\Enums\Nsid\Concerns\HasScopeHelpers;
66+77+enum BskyLabeler: string
88+{
99+ use HasScopeHelpers;
1010+ case GetServices = 'app.bsky.labeler.getServices';
1111+}
+13
src/Enums/Nsid/ChatActor.php
···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid;
44+55+use SocialDept\AtpClient\Enums\Nsid\Concerns\HasScopeHelpers;
66+77+enum ChatActor: string
88+{
99+ use HasScopeHelpers;
1010+ case GetActorMetadata = 'chat.bsky.actor.getActorMetadata';
1111+ case ExportAccountData = 'chat.bsky.actor.exportAccountData';
1212+ case DeleteAccount = 'chat.bsky.actor.deleteAccount';
1313+}
+22
src/Enums/Nsid/ChatConvo.php
···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid;
44+55+use SocialDept\AtpClient\Enums\Nsid\Concerns\HasScopeHelpers;
66+77+enum ChatConvo: string
88+{
99+ use HasScopeHelpers;
1010+ case GetConvo = 'chat.bsky.convo.getConvo';
1111+ case GetConvoForMembers = 'chat.bsky.convo.getConvoForMembers';
1212+ case ListConvos = 'chat.bsky.convo.listConvos';
1313+ case GetMessages = 'chat.bsky.convo.getMessages';
1414+ case SendMessage = 'chat.bsky.convo.sendMessage';
1515+ case SendMessageBatch = 'chat.bsky.convo.sendMessageBatch';
1616+ case DeleteMessageForSelf = 'chat.bsky.convo.deleteMessageForSelf';
1717+ case UpdateRead = 'chat.bsky.convo.updateRead';
1818+ case MuteConvo = 'chat.bsky.convo.muteConvo';
1919+ case UnmuteConvo = 'chat.bsky.convo.unmuteConvo';
2020+ case LeaveConvo = 'chat.bsky.convo.leaveConvo';
2121+ case GetLog = 'chat.bsky.convo.getLog';
2222+}
+34
src/Enums/Nsid/Concerns/HasScopeHelpers.php
···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid\Concerns;
44+55+trait HasScopeHelpers
66+{
77+ /**
88+ * Get the RPC scope format for this NSID.
99+ *
1010+ * @example BskyActor::GetProfile->rpc() // "rpc:app.bsky.actor.getProfile"
1111+ */
1212+ public function rpc(): string
1313+ {
1414+ return 'rpc:' . $this->value;
1515+ }
1616+1717+ /**
1818+ * Get the repo scope format for this NSID.
1919+ *
2020+ * @example BskyGraph::Follow->repo(['create']) // "repo:app.bsky.graph.follow?action=create"
2121+ * @example BskyFeed::Post->repo(['create', 'delete']) // "repo:app.bsky.feed.post?action=create&action=delete"
2222+ * @example BskyFeed::Post->repo() // "repo:app.bsky.feed.post"
2323+ */
2424+ public function repo(array $actions = []): string
2525+ {
2626+ $scope = 'repo:' . $this->value;
2727+2828+ if (! empty($actions)) {
2929+ $scope .= '?' . implode('&', array_map(fn ($action) => "action={$action}", $actions));
3030+ }
3131+3232+ return $scope;
3333+ }
3434+}
+18
src/Enums/Nsid/OzoneModeration.php
···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid;
44+55+use SocialDept\AtpClient\Enums\Nsid\Concerns\HasScopeHelpers;
66+77+enum OzoneModeration: string
88+{
99+ use HasScopeHelpers;
1010+ case GetEvent = 'tools.ozone.moderation.getEvent';
1111+ case GetEvents = 'tools.ozone.moderation.getEvents';
1212+ case GetRecord = 'tools.ozone.moderation.getRecord';
1313+ case GetRepo = 'tools.ozone.moderation.getRepo';
1414+ case QueryEvents = 'tools.ozone.moderation.queryEvents';
1515+ case QueryStatuses = 'tools.ozone.moderation.queryStatuses';
1616+ case SearchRepos = 'tools.ozone.moderation.searchRepos';
1717+ case EmitEvent = 'tools.ozone.moderation.emitEvent';
1818+}
+12
src/Enums/Nsid/OzoneServer.php
···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid;
44+55+use SocialDept\AtpClient\Enums\Nsid\Concerns\HasScopeHelpers;
66+77+enum OzoneServer: string
88+{
99+ use HasScopeHelpers;
1010+ case GetBlob = 'tools.ozone.server.getBlob';
1111+ case GetConfig = 'tools.ozone.server.getConfig';
1212+}
+15
src/Enums/Nsid/OzoneTeam.php
···11+<?php
22+33+namespace SocialDept\AtpClient\Enums\Nsid;
44+55+use SocialDept\AtpClient\Enums\Nsid\Concerns\HasScopeHelpers;
66+77+enum OzoneTeam: string
88+{
99+ use HasScopeHelpers;
1010+ case GetMember = 'tools.ozone.team.getMember';
1111+ case ListMembers = 'tools.ozone.team.listMembers';
1212+ case AddMember = 'tools.ozone.team.addMember';
1313+ case UpdateMember = 'tools.ozone.team.updateMember';
1414+ case DeleteMember = 'tools.ozone.team.deleteMember';
1515+}
+8-5
src/Http/HasHttp.php
···2233namespace SocialDept\AtpClient\Http;
4455+use BackedEnum;
56use Illuminate\Http\Client\Response as LaravelResponse;
67use Illuminate\Support\Facades\Http;
78use InvalidArgumentException;
···2728 * Make XRPC call
2829 */
2930 protected function call(
3030- string $endpoint,
3131+ string|BackedEnum $endpoint,
3132 string $method,
3233 ?array $params = null,
3334 ?array $body = null
3435 ): Response {
3636+ $endpoint = $endpoint instanceof BackedEnum ? $endpoint->value : $endpoint;
3537 $session = $this->sessions->ensureValid($this->did);
3638 $url = rtrim($session->pdsEndpoint(), '/').'/xrpc/'.$endpoint;
3739···102104 /**
103105 * Make GET request
104106 */
105105- public function get(string $endpoint, array $params = []): Response
107107+ public function get(string|BackedEnum $endpoint, array $params = []): Response
106108 {
107109 return $this->call($endpoint, 'GET', $params);
108110 }
···110112 /**
111113 * Make POST request
112114 */
113113- public function post(string $endpoint, array $body = []): Response
115115+ public function post(string|BackedEnum $endpoint, array $body = []): Response
114116 {
115117 return $this->call($endpoint, 'POST', null, $body);
116118 }
···118120 /**
119121 * Make DELETE request
120122 */
121121- public function delete(string $endpoint, array $params = []): Response
123123+ public function delete(string|BackedEnum $endpoint, array $params = []): Response
122124 {
123125 return $this->call($endpoint, 'DELETE', $params);
124126 }
···126128 /**
127129 * Make POST request with raw binary body (for blob uploads)
128130 */
129129- public function postBlob(string $endpoint, string $data, string $mimeType): Response
131131+ public function postBlob(string|BackedEnum $endpoint, string $data, string $mimeType): Response
130132 {
133133+ $endpoint = $endpoint instanceof BackedEnum ? $endpoint->value : $endpoint;
131134 $session = $this->sessions->ensureValid($this->did);
132135 $url = rtrim($session->pdsEndpoint(), '/').'/xrpc/'.$endpoint;
133136