@@ -41,6 +41,11 @@ async function fetchFromSlingshot<T>(
4141
4242/**
4343 * Fetch a record directly from PDS via Slingshot proxy
44+ *
45+ * Uses the ergonomic `com.bad-example.repo.getUriRecord` endpoint which accepts
46+ * a full at-uri instead of separate repo/collection/rkey parameters.
47+ *
48+ * @see https://slingshot.microcosm.blue/ for full API documentation
4449 */
4550export async function fetchRecordViaSlingshot (
4651 atUri : string
@@ -53,6 +58,13 @@ export async function fetchRecordViaSlingshot(
5358
5459/**
5560 * Resolve identity (DID/handle) via Slingshot
61+ *
62+ * Uses `com.bad-example.identity.resolveMiniDoc` which returns a compact identity
63+ * document with bi-directionally verified DID/handle and the user's PDS URL.
64+ * This is more convenient than the standard resolveHandle + describeRepo flow.
65+ *
66+ * @returns {did, handle, pds } or null if resolution fails
67+ * @see https://slingshot.microcosm.blue/ for full API documentation
5668 */
5769export async function resolveIdentityViaSlingshot (
5870 identifier : string
@@ -63,6 +75,17 @@ export async function resolveIdentityViaSlingshot(
6375 )
6476}
6577
78+ /**
79+ * Fetch engagement counts from Constellation backlink indexer
80+ *
81+ * Constellation indexes all social interactions (likes, reposts, replies) as backlinks
82+ * to posts. This provides real engagement counts even for AppView-suspended users.
83+ *
84+ * Note: Constellation only provides per-post engagement counts, not profile-level
85+ * aggregates (total followers, following, posts).
86+ *
87+ * @see https://constellation.microcosm.blue/ for more about Constellation
88+ */
6689export async function fetchConstellationCounts (
6790 atUri : string
6891) : Promise < ConstellationCounts > {
@@ -107,6 +130,13 @@ export function isAppViewError(error: any): boolean {
107130
108131/**
109132 * Build synthetic ProfileViewDetailed from PDS data
133+ *
134+ * Fetches the user's profile record from their PDS via Slingshot and constructs
135+ * an AppView-compatible ProfileViewDetailed object.
136+ *
137+ * LIMITATION: Profile-level aggregate counts (followers, following, posts) are not
138+ * available from Slingshot or Constellation and are set to undefined. These would
139+ * require AppView-style indexing infrastructure.
110140 */
111141export async function buildSyntheticProfileView (
112142 did : string ,
@@ -127,9 +157,9 @@ export async function buildSyntheticProfileView(
127157 banner : record ?. value ?. banner
128158 ? `https://cdn.bsky.app/img/banner/plain/${ did } /${ record . value . banner . ref . $link } @jpeg`
129159 : undefined ,
130- followersCount : undefined , // Not available from PDS
131- followsCount : undefined , // Not available from PDS
132- postsCount : undefined , // Not available from PDS
160+ followersCount : undefined , // Not available from PDS or Constellation
161+ followsCount : undefined , // Not available from PDS or Constellation
162+ postsCount : undefined , // Not available from PDS or Constellation
133163 indexedAt : new Date ( ) . toISOString ( ) ,
134164 viewer : { } ,
135165 labels : [ ] ,
@@ -170,6 +200,18 @@ export async function buildSyntheticPostView(
170200/**
171201 * Build synthetic feed page from PDS data
172202 * This is used for infinite queries that need paginated results
203+ *
204+ * IMPORTANT: This function bypasses Slingshot and fetches directly from the user's PDS
205+ * because Slingshot does not support the `com.atproto.repo.listRecords` endpoint needed
206+ * for bulk record fetching.
207+ *
208+ * Trade-off: No caching benefit from Slingshot, but we can still provide author feed
209+ * functionality for AppView-suspended users.
210+ *
211+ * Each post in the feed will trigger:
212+ * - 1 record fetch via Slingshot (for the full post data, cached)
213+ * - 1 Constellation request (for engagement counts)
214+ * - Profile fetch (cached after first request)
173215 */
174216export async function buildSyntheticFeedPage (
175217 did : string ,
@@ -181,6 +223,7 @@ export async function buildSyntheticFeedPage(
181223 const cursorParam = cursor ? `&cursor=${ encodeURIComponent ( cursor ) } ` : ''
182224
183225 // Fetch posts directly from PDS using com.atproto.repo.listRecords
226+ // NOTE: This bypasses Slingshot because listRecords is not available there
184227 const url = `${ pdsUrl } /xrpc/com.atproto.repo.listRecords?repo=${ did } &collection=app.bsky.feed.post&limit=${ limit } ${ cursorParam } `
185228 const res = await fetch ( url )
186229
0 commit comments