Skip to content

Add relationshipLookup, bskyProfileIfExists, and BskyCDN read helpers - #58

Merged
germ-mark merged 1 commit into
llm/doh-wellknown-handle-resolversfrom
llm/bsky-read-helpers
Sep 23, 2026
Merged

germ-mark merged 1 commit into
llm/doh-wellknown-handle-resolversfrom
llm/bsky-read-helpers

Conversation

@germ-mark

Copy link
Copy Markdown
Contributor

Stacked on #57. Review and merge that first; this PR's diff is just the one commit on top.

  • relationshipLookup(actor:others:) dedupes, chunks at 30, and returns a GetRelationships.Lookup with found and notFound per requested DID. The existing getRelationships(actor:subjects:) drops not-found subjects with a compactMap. The AppView returns a relationship entry for any well-formed DID, so found doesn't mean the account exists; use bskyProfileIfExists for that. If a response names a different actor, it throws actorMismatch from the now-public GetRelationships.Errors.
  • Off-by-one fix: GetRelationships.Parameters rejected exactly 30 others, but the lexicon's others.maxLength is 30.
  • bskyProfileIfExists(actor:) returns nil for the AppView's 400 InvalidRequest "Profile not found" (getProfile's lexicon declares no errors). Anything else, including deactivated or suspended accounts, still throws.
  • Atproto.BskyCDN.imageURL(_:did:blob:host:) builds cdn.bsky.app/img/<avatar|banner>/plain/<did>/<cid>@jpeg from a record Blob. The DID and CID are percent-encoded as single path segments.

Everything is additive except the maxOthers fix and making GetRelationships.Errors public.

Testing: new tests cover chunking boundaries (30/31/60/61), the found/not-found split (including unrequested, omitted and handle-form entries), dedupe, the per-chunk actor check, the getProfile not-found parse path, and CDN path traversal and host handling. All were mutation-checked. swift test --skip OnlineTests, strict lint and an Android cross-compile pass.

🤖 Generated with Claude Code

Three additive helpers on Atproto.XRPC.BskyAppCallable:
relationshipLookup(actor:others:) dedupes/chunks app.bsky.graph.getRelationships
at the lexicon's 30-subject limit and reports not-found subjects rather than
dropping them (not an account-existence check - the AppView returns a
relationship entry for any well-formed DID); bskyProfileIfExists(actor:) maps
getProfile's undeclared not-found shape (400 InvalidRequest, "Profile not
found") to nil; and Atproto.BskyCDN.imageURL(_:did:blob:host:) builds CDN
image URLs from a blob reference with explicit RFC 3986 path-segment encoding
so a crafted DID/CID can't escape its segment.

Also fixes GetRelationships.Parameters.init to accept exactly 30 others (the
lexicon's own maxLength, previously rejected) and makes GetRelationships.Errors
public, since it's already thrown by public API.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Sep 23, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 18c070d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@germ-network/atprotoclient Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@germ-mark
germ-mark merged commit 1b4b358 into llm/doh-wellknown-handle-resolvers Sep 23, 2026
11 checks passed
@germ-mark
germ-mark deleted the llm/bsky-read-helpers branch September 23, 2026 22:43
@github-actions github-actions Bot mentioned this pull request Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant