diff --git a/packages/bsky/src/api/app/bsky/actor/getSuggestions.ts b/packages/bsky/src/api/app/bsky/actor/getSuggestions.ts index 34add3f7926..d209a6f4cef 100644 --- a/packages/bsky/src/api/app/bsky/actor/getSuggestions.ts +++ b/packages/bsky/src/api/app/bsky/actor/getSuggestions.ts @@ -124,7 +124,7 @@ const presentation = (input: { }) => { const { ctx, skeleton, hydration } = input const actors = mapDefined(skeleton.dids, (did) => - ctx.views.profile(did, hydration), + ctx.views.profileKnownFollowers(did, hydration), ) return { actors, diff --git a/packages/bsky/src/views/index.ts b/packages/bsky/src/views/index.ts index d93d99d8446..8079f36dce2 100644 --- a/packages/bsky/src/views/index.ts +++ b/packages/bsky/src/views/index.ts @@ -213,6 +213,29 @@ export class Views { } } + profileKnownFollowers( + did: string, + state: HydrationState, + ): ProfileView | undefined { + const actor = state.actors?.get(did) + if (!actor) return + const baseView = this.profile(did, state) + if (!baseView) return + const knownFollowersSkeleton = state.knownFollowers?.get(did) + const knownFollowers = knownFollowersSkeleton + ? this.knownFollowers(knownFollowersSkeleton, state, did) + : undefined + return { + ...baseView, + viewer: baseView.viewer + ? { + ...baseView.viewer, + knownFollowers, + } + : undefined, + } + } + profileViewer( did: string, state: HydrationState, @@ -250,6 +273,10 @@ export class Views { if (blocks && blocks.get(did) === true) { return undefined } + if (this.actorIsNoHosted(did, state)) { + // @TODO only needed right now to work around getProfile's { includeTakedowns: true } + return undefined + } return this.profileBasic(did, state) }) return { count: knownFollowers.count, followers } diff --git a/packages/pds/tests/proxied/__snapshots__/views.test.ts.snap b/packages/pds/tests/proxied/__snapshots__/views.test.ts.snap index e312cb014da..ae824a89864 100644 --- a/packages/pds/tests/proxied/__snapshots__/views.test.ts.snap +++ b/packages/pds/tests/proxied/__snapshots__/views.test.ts.snap @@ -187,22 +187,90 @@ Object { "viewer": Object { "blockedBy": false, "followedBy": "record(0)", + "knownFollowers": Object { + "count": 1, + "followers": Array [ + Object { + "avatar": "https://bsky.public.url/img/avatar/plain/user(3)/cids(0)@jpeg", + "createdAt": "1970-01-01T00:00:00.000Z", + "did": "user(2)", + "displayName": "ali", + "handle": "alice.test", + "labels": Array [ + Object { + "cid": "cids(1)", + "cts": "1970-01-01T00:00:00.000Z", + "src": "user(2)", + "uri": "record(3)", + "val": "self-label-a", + }, + Object { + "cid": "cids(1)", + "cts": "1970-01-01T00:00:00.000Z", + "src": "user(2)", + "uri": "record(3)", + "val": "self-label-b", + }, + ], + "viewer": Object { + "blockedBy": false, + "followedBy": "record(2)", + "following": "record(1)", + "muted": false, + }, + }, + ], + }, "muted": false, }, }, Object { - "did": "user(2)", + "did": "user(4)", "handle": "dan.test", "labels": Array [ Object { "cts": "1970-01-01T00:00:00.000Z", "src": "did:example:labeler", - "uri": "user(2)", + "uri": "user(4)", "val": "repo-action-label", }, ], "viewer": Object { "blockedBy": false, + "knownFollowers": Object { + "count": 1, + "followers": Array [ + Object { + "avatar": "https://bsky.public.url/img/avatar/plain/user(3)/cids(0)@jpeg", + "createdAt": "1970-01-01T00:00:00.000Z", + "did": "user(2)", + "displayName": "ali", + "handle": "alice.test", + "labels": Array [ + Object { + "cid": "cids(1)", + "cts": "1970-01-01T00:00:00.000Z", + "src": "user(2)", + "uri": "record(3)", + "val": "self-label-a", + }, + Object { + "cid": "cids(1)", + "cts": "1970-01-01T00:00:00.000Z", + "src": "user(2)", + "uri": "record(3)", + "val": "self-label-b", + }, + ], + "viewer": Object { + "blockedBy": false, + "followedBy": "record(2)", + "following": "record(1)", + "muted": false, + }, + }, + ], + }, "muted": false, }, }, diff --git a/services/bsky/README.md b/services/bsky/README.md index fea1bf3c602..fa512b03e53 100644 --- a/services/bsky/README.md +++ b/services/bsky/README.md @@ -5,7 +5,7 @@ This is the service entrypoint for the bsky appview. The entrypoint command shou - `BSKY_PUBLIC_URL` - (required) the public url of the appview, e.g. `https://api.bsky.app`. - `BSKY_DID_PLC_URL` - (required) the url of the PLC service used for looking up did documents, e.g. `https://plc.directory`. - `BSKY_DATAPLANE_URL` - (required) the url where the backing dataplane service lives. -- `BSKY_SERVICE_SIGNING_KEY` - (required) the public signing key in the form of a `did:key`, used for service-to-service auth. Advertised in the appview's `did:web`` document. +- `BSKY_SERVICE_SIGNING_KEY` - (required) the public signing key in the form of a `did:key`, used for service-to-service auth. Advertised in the appview's `did:web` document. - `BSKY_ADMIN_PASSWORDS` - (alt. `BSKY_ADMIN_PASSWORD`) (required) comma-separated list of admin passwords used for role-based auth. - `NODE_ENV` - (recommended) for production usage, should be set to `production`. Otherwise all responses are validated on their way out. There may be other effects of not setting this to `production`, as dependencies may also implement debug modes based on its value. - `BSKY_VERSION` - (recommended) version of the bsky service. This is advertised by the health endpoint.