From e3063041a32ec6feb8e8cf48a96da99daec48707 Mon Sep 17 00:00:00 2001 From: Daniel Holmgren Date: Fri, 26 Apr 2024 16:30:08 -0500 Subject: [PATCH] Feed context & sendInteractions impl (#2402) * forward feedContext on getFeed * add sendInteractions to PDS * fix typeof * add feedContext to snapshots --------- Co-authored-by: Devin Ivy --- .../bsky/src/api/app/bsky/feed/getFeed.ts | 33 +++++++++---------- .../feed-generation.test.ts.snap | 11 +++++++ packages/bsky/tests/feed-generation.test.ts | 2 +- packages/pds/src/api/app/bsky/feed/index.ts | 2 ++ .../src/api/app/bsky/feed/sendInteractions.ts | 13 ++++++++ 5 files changed, 43 insertions(+), 18 deletions(-) create mode 100644 packages/pds/src/api/app/bsky/feed/sendInteractions.ts diff --git a/packages/bsky/src/api/app/bsky/feed/getFeed.ts b/packages/bsky/src/api/app/bsky/feed/getFeed.ts index bbd479e1636..03693482872 100644 --- a/packages/bsky/src/api/app/bsky/feed/getFeed.ts +++ b/packages/bsky/src/api/app/bsky/feed/getFeed.ts @@ -85,7 +85,7 @@ const skeleton = async ( return { cursor, - items: algoItems.map(toFeedItem), + items: algoItems, timerSkele: timerSkele.stop(), timerHydr: new ServerTimer('hydr').start(), resHeaders, @@ -126,7 +126,12 @@ const presentation = ( ) => { const { ctx, params, skeleton, hydration } = inputs const feed = mapDefined(skeleton.items, (item) => { - return ctx.views.feedViewPost(item, hydration) + const post = ctx.views.feedViewPost(item, hydration) + if (!post) return + return { + ...post, + feedContext: item.feedContext, + } }).slice(0, params.limit) return { feed, @@ -146,7 +151,7 @@ type Params = GetFeedParams & { } type Skeleton = { - items: FeedItem[] + items: AlgoResponseItem[] passthrough: Record // pass through additional items in feedgen response resHeaders?: Record cursor?: string @@ -228,9 +233,12 @@ const skeletonFromFeedGen = async ( const { feed: feedSkele, ...skele } = skeleton const feedItems = feedSkele.map((item) => ({ - itemUri: - typeof item.reason?.repost === 'string' ? item.reason.repost : item.post, - postUri: item.post, + post: { uri: item.post }, + repost: + typeof item.reason?.repost === 'string' + ? { uri: item.reason.repost } + : undefined, + feedContext: item.feedContext, })) return { ...skele, resHeaders, feedItems } @@ -242,15 +250,6 @@ export type AlgoResponse = { cursor?: string } -export type AlgoResponseItem = { - itemUri: string - postUri: string +export type AlgoResponseItem = FeedItem & { + feedContext?: string } - -export const toFeedItem = (feedItem: AlgoResponseItem): FeedItem => ({ - post: { uri: feedItem.postUri }, - repost: - feedItem.itemUri === feedItem.postUri - ? undefined - : { uri: feedItem.itemUri }, -}) diff --git a/packages/bsky/tests/__snapshots__/feed-generation.test.ts.snap b/packages/bsky/tests/__snapshots__/feed-generation.test.ts.snap index 0c14e2af095..967e22c3f4d 100644 --- a/packages/bsky/tests/__snapshots__/feed-generation.test.ts.snap +++ b/packages/bsky/tests/__snapshots__/feed-generation.test.ts.snap @@ -342,6 +342,7 @@ Array [ exports[`feed generation getFeed paginates, handling replies and reposts. 1`] = ` Array [ Object { + "feedContext": "item-0", "post": Object { "author": Object { "avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)@jpeg", @@ -401,6 +402,7 @@ Array [ }, }, Object { + "feedContext": "item-1", "post": Object { "author": Object { "avatar": "https://bsky.public.url/img/avatar/plain/user(3)/cids(1)@jpeg", @@ -435,6 +437,7 @@ Array [ }, }, Object { + "feedContext": "item-2", "post": Object { "author": Object { "did": "user(4)", @@ -554,6 +557,7 @@ Array [ }, }, Object { + "feedContext": "item-4", "post": Object { "author": Object { "did": "user(4)", @@ -678,6 +682,7 @@ Array [ }, }, Object { + "feedContext": "item-5", "post": Object { "author": Object { "did": "user(6)", @@ -865,6 +870,7 @@ Array [ exports[`feed generation getFeed resolves basic feed contents without auth. 1`] = ` Array [ Object { + "feedContext": "item-0", "post": Object { "author": Object { "avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)@jpeg", @@ -919,6 +925,7 @@ Array [ }, }, Object { + "feedContext": "item-2", "post": Object { "author": Object { "did": "user(2)", @@ -1023,6 +1030,7 @@ Array [ }, }, Object { + "feedContext": "item-4", "post": Object { "author": Object { "did": "user(2)", @@ -1135,6 +1143,7 @@ Array [ exports[`feed generation getFeed resolves basic feed contents. 1`] = ` Array [ Object { + "feedContext": "item-0", "post": Object { "author": Object { "avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)@jpeg", @@ -1194,6 +1203,7 @@ Array [ }, }, Object { + "feedContext": "item-2", "post": Object { "author": Object { "did": "user(2)", @@ -1313,6 +1323,7 @@ Array [ }, }, Object { + "feedContext": "item-4", "post": Object { "author": Object { "did": "user(2)", diff --git a/packages/bsky/tests/feed-generation.test.ts b/packages/bsky/tests/feed-generation.test.ts index 3120f45669c..df3d5a1b9e8 100644 --- a/packages/bsky/tests/feed-generation.test.ts +++ b/packages/bsky/tests/feed-generation.test.ts @@ -543,7 +543,7 @@ describe('feed generation', () => { repost: sc.reposts[sc.dids.carol][0].uriStr, }, }, - ] + ].map((item, i) => ({ ...item, feedContext: `item-${i}` })) // add a deterministic context to test passthrough const offset = cursor ? parseInt(cursor, 10) : 0 const fullFeed = candidates.filter((_, i) => { if (feedName === 'even') { diff --git a/packages/pds/src/api/app/bsky/feed/index.ts b/packages/pds/src/api/app/bsky/feed/index.ts index 026ce86f612..e143c003f99 100644 --- a/packages/pds/src/api/app/bsky/feed/index.ts +++ b/packages/pds/src/api/app/bsky/feed/index.ts @@ -14,6 +14,7 @@ import getRepostedBy from './getRepostedBy' import getSuggestedFeeds from './getSuggestedFeeds' import getTimeline from './getTimeline' import searchPosts from './searchPosts' +import sendInteractions from './sendInteractions' export default function (server: Server, ctx: AppContext) { getActorFeeds(server, ctx) @@ -30,4 +31,5 @@ export default function (server: Server, ctx: AppContext) { getSuggestedFeeds(server, ctx) getTimeline(server, ctx) searchPosts(server, ctx) + sendInteractions(server, ctx) } diff --git a/packages/pds/src/api/app/bsky/feed/sendInteractions.ts b/packages/pds/src/api/app/bsky/feed/sendInteractions.ts new file mode 100644 index 00000000000..fec297fad0c --- /dev/null +++ b/packages/pds/src/api/app/bsky/feed/sendInteractions.ts @@ -0,0 +1,13 @@ +import { Server } from '../../../../lexicon' +import AppContext from '../../../../context' +import { pipethroughProcedure } from '../../../../pipethrough' + +export default function (server: Server, ctx: AppContext) { + server.app.bsky.feed.sendInteractions({ + auth: ctx.authVerifier.access, + handler: async ({ input, auth, req }) => { + const requester = auth.credentials.did + return pipethroughProcedure(ctx, req, input.body, requester) + }, + }) +}