diff --git a/.changeset/plenty-turtles-shop.md b/.changeset/plenty-turtles-shop.md new file mode 100644 index 00000000..20eb27db --- /dev/null +++ b/.changeset/plenty-turtles-shop.md @@ -0,0 +1,6 @@ +--- +"@atproto/bsky": patch +"@atproto/api": patch +--- + +Add `threadgate: ThreadgateView` to response from `getPostThread` diff --git a/lexicons/app/bsky/feed/getPostThread.json b/lexicons/app/bsky/feed/getPostThread.json index 89e99d9c..7efab15f 100644 --- a/lexicons/app/bsky/feed/getPostThread.json +++ b/lexicons/app/bsky/feed/getPostThread.json @@ -43,6 +43,10 @@ "app.bsky.feed.defs#notFoundPost", "app.bsky.feed.defs#blockedPost" ] + }, + "threadgate": { + "type": "ref", + "ref": "app.bsky.feed.defs#threadgateView" } } } diff --git a/packages/api/src/client/lexicons.ts b/packages/api/src/client/lexicons.ts index 8af84f4b..40bdfa36 100644 --- a/packages/api/src/client/lexicons.ts +++ b/packages/api/src/client/lexicons.ts @@ -6251,6 +6251,10 @@ export const schemaDict = { 'lex:app.bsky.feed.defs#blockedPost', ], }, + threadgate: { + type: 'ref', + ref: 'lex:app.bsky.feed.defs#threadgateView', + }, }, }, }, diff --git a/packages/api/src/client/types/app/bsky/feed/getPostThread.ts b/packages/api/src/client/types/app/bsky/feed/getPostThread.ts index 930db4c1..df012607 100644 --- a/packages/api/src/client/types/app/bsky/feed/getPostThread.ts +++ b/packages/api/src/client/types/app/bsky/feed/getPostThread.ts @@ -25,6 +25,7 @@ export interface OutputSchema { | AppBskyFeedDefs.NotFoundPost | AppBskyFeedDefs.BlockedPost | { $type: string; [k: string]: unknown } + threadgate?: AppBskyFeedDefs.ThreadgateView [k: string]: unknown } diff --git a/packages/bsky/src/api/app/bsky/feed/getPostThread.ts b/packages/bsky/src/api/app/bsky/feed/getPostThread.ts index 5342cb0d..c44eee86 100644 --- a/packages/bsky/src/api/app/bsky/feed/getPostThread.ts +++ b/packages/bsky/src/api/app/bsky/feed/getPostThread.ts @@ -1,6 +1,10 @@ import { InvalidRequestError } from '@atproto/xrpc-server' import { Server } from '../../../../lexicon' -import { isNotFoundPost } from '../../../../lexicon/types/app/bsky/feed/defs' +import { + isNotFoundPost, + isThreadViewPost, +} from '../../../../lexicon/types/app/bsky/feed/defs' +import { isRecord as isPostRecord } from '../../../../lexicon/types/app/bsky/feed/post' import { QueryParams, OutputSchema, @@ -17,6 +21,7 @@ import { import { HydrateCtx, Hydrator } from '../../../../hydration/hydrator' import { Views } from '../../../../views' import { DataPlaneClient, isDataplaneError, Code } from '../../../../data-plane' +import { postUriToThreadgateUri } from '../../../../util/uris' export default function (server: Server, ctx: AppContext) { const getPostThread = createPipeline( @@ -110,7 +115,13 @@ const presentation = ( // @TODO technically this could be returned as a NotFoundPost based on lexicon throw new InvalidRequestError(`Post not found: ${params.uri}`, 'NotFound') } - return { thread } + const rootUri = + hydration.posts?.get(params.uri)?.record.reply?.root.uri ?? params.uri + const threadgate = ctx.views.threadgate( + postUriToThreadgateUri(rootUri), + hydration, + ) + return { thread, threadgate } } type Context = { diff --git a/packages/bsky/src/lexicon/lexicons.ts b/packages/bsky/src/lexicon/lexicons.ts index e0c1d4f9..05254f17 100644 --- a/packages/bsky/src/lexicon/lexicons.ts +++ b/packages/bsky/src/lexicon/lexicons.ts @@ -6251,6 +6251,10 @@ export const schemaDict = { 'lex:app.bsky.feed.defs#blockedPost', ], }, + threadgate: { + type: 'ref', + ref: 'lex:app.bsky.feed.defs#threadgateView', + }, }, }, }, diff --git a/packages/bsky/src/lexicon/types/app/bsky/feed/getPostThread.ts b/packages/bsky/src/lexicon/types/app/bsky/feed/getPostThread.ts index ae232fd9..76897719 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/feed/getPostThread.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/feed/getPostThread.ts @@ -26,6 +26,7 @@ export interface OutputSchema { | AppBskyFeedDefs.NotFoundPost | AppBskyFeedDefs.BlockedPost | { $type: string; [k: string]: unknown } + threadgate?: AppBskyFeedDefs.ThreadgateView [k: string]: unknown } diff --git a/packages/bsky/tests/views/threadgating.test.ts b/packages/bsky/tests/views/threadgating.test.ts index 02b332b6..2a459e24 100644 --- a/packages/bsky/tests/views/threadgating.test.ts +++ b/packages/bsky/tests/views/threadgating.test.ts @@ -44,16 +44,17 @@ describe('views with thread gating', () => { it('applies gate for empty rules.', async () => { const post = await sc.post(sc.dids.carol, 'empty rules') - await pdsAgent.api.app.bsky.feed.threadgate.create( - { repo: sc.dids.carol, rkey: post.ref.uri.rkey }, - { post: post.ref.uriStr, createdAt: iso(), allow: [] }, - sc.getHeaders(sc.dids.carol), - ) + const { uri: threadgateUri } = + await pdsAgent.api.app.bsky.feed.threadgate.create( + { repo: sc.dids.carol, rkey: post.ref.uri.rkey }, + { post: post.ref.uriStr, createdAt: iso(), allow: [] }, + sc.getHeaders(sc.dids.carol), + ) await network.processAll() await sc.reply(sc.dids.alice, post.ref, post.ref, 'empty rules reply') await network.processAll() const { - data: { thread }, + data: { thread, threadgate }, } = await agent.api.app.bsky.feed.getPostThread( { uri: post.ref.uriStr }, { @@ -67,6 +68,7 @@ describe('views with thread gating', () => { expect(forSnapshot(thread.post.threadgate)).toMatchSnapshot() expect(thread.post.viewer?.replyDisabled).toBe(true) expect(thread.replies?.length).toEqual(0) + expect(threadgate?.uri).toEqual(threadgateUri) await checkReplyDisabled(post.ref.uriStr, sc.dids.alice, true) }) diff --git a/packages/ozone/src/lexicon/lexicons.ts b/packages/ozone/src/lexicon/lexicons.ts index 8af84f4b..40bdfa36 100644 --- a/packages/ozone/src/lexicon/lexicons.ts +++ b/packages/ozone/src/lexicon/lexicons.ts @@ -6251,6 +6251,10 @@ export const schemaDict = { 'lex:app.bsky.feed.defs#blockedPost', ], }, + threadgate: { + type: 'ref', + ref: 'lex:app.bsky.feed.defs#threadgateView', + }, }, }, }, diff --git a/packages/ozone/src/lexicon/types/app/bsky/feed/getPostThread.ts b/packages/ozone/src/lexicon/types/app/bsky/feed/getPostThread.ts index ae232fd9..76897719 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/feed/getPostThread.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/feed/getPostThread.ts @@ -26,6 +26,7 @@ export interface OutputSchema { | AppBskyFeedDefs.NotFoundPost | AppBskyFeedDefs.BlockedPost | { $type: string; [k: string]: unknown } + threadgate?: AppBskyFeedDefs.ThreadgateView [k: string]: unknown } diff --git a/packages/pds/src/lexicon/lexicons.ts b/packages/pds/src/lexicon/lexicons.ts index 8af84f4b..40bdfa36 100644 --- a/packages/pds/src/lexicon/lexicons.ts +++ b/packages/pds/src/lexicon/lexicons.ts @@ -6251,6 +6251,10 @@ export const schemaDict = { 'lex:app.bsky.feed.defs#blockedPost', ], }, + threadgate: { + type: 'ref', + ref: 'lex:app.bsky.feed.defs#threadgateView', + }, }, }, }, diff --git a/packages/pds/src/lexicon/types/app/bsky/feed/getPostThread.ts b/packages/pds/src/lexicon/types/app/bsky/feed/getPostThread.ts index ae232fd9..76897719 100644 --- a/packages/pds/src/lexicon/types/app/bsky/feed/getPostThread.ts +++ b/packages/pds/src/lexicon/types/app/bsky/feed/getPostThread.ts @@ -26,6 +26,7 @@ export interface OutputSchema { | AppBskyFeedDefs.NotFoundPost | AppBskyFeedDefs.BlockedPost | { $type: string; [k: string]: unknown } + threadgate?: AppBskyFeedDefs.ThreadgateView [k: string]: unknown }