@atproto/bsky 0.0.15 → 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/api/com/atproto/moderation/util.d.ts +4 -3
- package/dist/context.d.ts +15 -0
- package/dist/db/index.js +26 -1
- package/dist/db/index.js.map +3 -3
- package/dist/db/migrations/20231003T202833377Z-create-moderation-subject-status.d.ts +3 -0
- package/dist/db/migrations/index.d.ts +1 -0
- package/dist/db/pagination.d.ts +2 -1
- package/dist/db/{periodic-moderation-action-reversal.d.ts → periodic-moderation-event-reversal.d.ts} +3 -5
- package/dist/db/tables/moderation.d.ts +24 -34
- package/dist/feed-gen/types.d.ts +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2750 -2121
- package/dist/index.js.map +3 -3
- package/dist/lexicon/index.d.ts +11 -18
- package/dist/lexicon/lexicons.d.ts +414 -399
- package/dist/lexicon/types/app/bsky/feed/defs.d.ts +1 -7
- package/dist/lexicon/types/app/bsky/graph/defs.d.ts +1 -0
- package/dist/lexicon/types/com/atproto/admin/defs.d.ts +114 -48
- package/dist/lexicon/types/com/atproto/admin/{takeModerationAction.d.ts → emitModerationEvent.d.ts} +5 -6
- package/dist/lexicon/types/com/atproto/admin/{getModerationAction.d.ts → getModerationEvent.d.ts} +1 -1
- package/dist/lexicon/types/com/atproto/admin/{getModerationActions.d.ts → queryModerationEvents.d.ts} +5 -1
- package/dist/lexicon/types/com/atproto/admin/{getModerationReports.d.ts → queryModerationStatuses.d.ts} +12 -6
- package/dist/lexicon/types/com/atproto/admin/sendEmail.d.ts +1 -0
- package/dist/migrate-moderation-data.d.ts +1 -0
- package/dist/services/actor/views.d.ts +2 -5
- package/dist/services/feed/index.d.ts +1 -0
- package/dist/services/feed/util.d.ts +9 -1
- package/dist/services/feed/views.d.ts +6 -17
- package/dist/services/graph/index.d.ts +5 -29
- package/dist/services/graph/types.d.ts +1 -0
- package/dist/services/moderation/index.d.ts +135 -72
- package/dist/services/moderation/pagination.d.ts +36 -0
- package/dist/services/moderation/status.d.ts +13 -0
- package/dist/services/moderation/types.d.ts +35 -0
- package/dist/services/moderation/views.d.ts +18 -14
- package/dist/util/debug.d.ts +1 -1
- package/package.json +11 -11
- package/src/api/app/bsky/feed/getActorFeeds.ts +2 -1
- package/src/api/app/bsky/feed/getActorLikes.ts +1 -3
- package/src/api/app/bsky/feed/getAuthorFeed.ts +1 -3
- package/src/api/app/bsky/feed/getFeed.ts +9 -9
- package/src/api/app/bsky/feed/getFeedGenerator.ts +3 -0
- package/src/api/app/bsky/feed/getFeedGenerators.ts +2 -1
- package/src/api/app/bsky/feed/getListFeed.ts +1 -3
- package/src/api/app/bsky/feed/getPostThread.ts +15 -54
- package/src/api/app/bsky/feed/getPosts.ts +21 -18
- package/src/api/app/bsky/feed/getSuggestedFeeds.ts +2 -1
- package/src/api/app/bsky/feed/getTimeline.ts +1 -3
- package/src/api/app/bsky/feed/searchPosts.ts +20 -17
- package/src/api/app/bsky/graph/getList.ts +6 -3
- package/src/api/app/bsky/graph/getListBlocks.ts +3 -2
- package/src/api/app/bsky/graph/getListMutes.ts +2 -1
- package/src/api/app/bsky/graph/getLists.ts +2 -1
- package/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +3 -1
- package/src/api/blob-resolver.ts +6 -11
- package/src/api/com/atproto/admin/emitModerationEvent.ts +220 -0
- package/src/api/com/atproto/admin/{getModerationActions.ts → getModerationEvent.ts} +5 -11
- package/src/api/com/atproto/admin/getRecord.ts +1 -0
- package/src/api/com/atproto/admin/{getModerationReports.ts → queryModerationEvents.ts} +13 -16
- package/src/api/com/atproto/admin/queryModerationStatuses.ts +55 -0
- package/src/api/com/atproto/moderation/createReport.ts +9 -7
- package/src/api/com/atproto/moderation/util.ts +38 -20
- package/src/api/index.ts +8 -14
- package/src/auth.ts +29 -21
- package/src/auto-moderator/index.ts +26 -19
- package/src/context.ts +4 -0
- package/src/db/migrations/20231003T202833377Z-create-moderation-subject-status.ts +123 -0
- package/src/db/migrations/index.ts +1 -0
- package/src/db/pagination.ts +26 -3
- package/src/db/{periodic-moderation-action-reversal.ts → periodic-moderation-event-reversal.ts} +50 -46
- package/src/db/tables/moderation.ts +35 -52
- package/src/feed-gen/best-of-follows.ts +6 -3
- package/src/feed-gen/bsky-team.ts +1 -1
- package/src/feed-gen/hot-classic.ts +1 -1
- package/src/feed-gen/mutuals.ts +6 -2
- package/src/feed-gen/types.ts +1 -1
- package/src/feed-gen/whats-hot.ts +1 -1
- package/src/feed-gen/with-friends.ts +7 -3
- package/src/index.ts +2 -1
- package/src/lexicon/index.ts +30 -67
- package/src/lexicon/lexicons.ts +526 -491
- package/src/lexicon/types/app/bsky/feed/defs.ts +1 -18
- package/src/lexicon/types/app/bsky/graph/defs.ts +1 -0
- package/src/lexicon/types/com/atproto/admin/defs.ts +276 -84
- package/src/lexicon/types/com/atproto/admin/{takeModerationAction.ts → emitModerationEvent.ts} +13 -11
- package/src/lexicon/types/com/atproto/admin/{getModerationReport.ts → getModerationEvent.ts} +1 -1
- package/src/lexicon/types/com/atproto/admin/{getModerationActions.ts → queryModerationEvents.ts} +8 -1
- package/src/lexicon/types/com/atproto/admin/{getModerationReports.ts → queryModerationStatuses.ts} +21 -14
- package/src/lexicon/types/com/atproto/admin/sendEmail.ts +1 -0
- package/src/migrate-moderation-data.ts +414 -0
- package/src/services/actor/views.ts +5 -14
- package/src/services/feed/index.ts +26 -7
- package/src/services/feed/util.ts +47 -19
- package/src/services/feed/views.ts +68 -4
- package/src/services/graph/index.ts +21 -3
- package/src/services/graph/types.ts +1 -0
- package/src/services/indexing/plugins/block.ts +2 -3
- package/src/services/indexing/plugins/feed-generator.ts +2 -3
- package/src/services/indexing/plugins/follow.ts +2 -3
- package/src/services/indexing/plugins/like.ts +2 -3
- package/src/services/indexing/plugins/list-block.ts +2 -3
- package/src/services/indexing/plugins/list-item.ts +2 -3
- package/src/services/indexing/plugins/list.ts +2 -3
- package/src/services/indexing/plugins/post.ts +3 -4
- package/src/services/indexing/plugins/repost.ts +2 -3
- package/src/services/indexing/plugins/thread-gate.ts +2 -3
- package/src/services/label/index.ts +2 -3
- package/src/services/moderation/index.ts +380 -395
- package/src/services/moderation/pagination.ts +96 -0
- package/src/services/moderation/status.ts +244 -0
- package/src/services/moderation/types.ts +49 -0
- package/src/services/moderation/views.ts +278 -329
- package/src/util/debug.ts +2 -2
- package/tests/__snapshots__/feed-generation.test.ts.snap +322 -6
- package/tests/__snapshots__/indexing.test.ts.snap +0 -6
- package/tests/admin/__snapshots__/get-record.test.ts.snap +30 -132
- package/tests/admin/__snapshots__/get-repo.test.ts.snap +14 -60
- package/tests/admin/__snapshots__/moderation-events.test.ts.snap +146 -0
- package/tests/admin/__snapshots__/moderation-statuses.test.ts.snap +64 -0
- package/tests/admin/__snapshots__/moderation.test.ts.snap +0 -125
- package/tests/admin/get-record.test.ts +5 -9
- package/tests/admin/get-repo.test.ts +5 -9
- package/tests/admin/moderation-events.test.ts +221 -0
- package/tests/admin/moderation-statuses.test.ts +145 -0
- package/tests/admin/moderation.test.ts +512 -860
- package/tests/admin/repo-search.test.ts +2 -3
- package/tests/auto-moderator/fuzzy-matcher.test.ts +2 -1
- package/tests/auto-moderator/takedowns.test.ts +45 -18
- package/tests/feed-generation.test.ts +57 -9
- package/tests/views/__snapshots__/block-lists.test.ts.snap +3 -9
- package/tests/views/__snapshots__/blocks.test.ts.snap +0 -9
- package/tests/views/__snapshots__/mute-lists.test.ts.snap +5 -5
- package/tests/views/__snapshots__/mutes.test.ts.snap +0 -3
- package/tests/views/__snapshots__/thread.test.ts.snap +0 -30
- package/tests/views/actor-search.test.ts +2 -3
- package/tests/views/author-feed.test.ts +42 -36
- package/tests/views/follows.test.ts +40 -35
- package/tests/views/list-feed.test.ts +17 -9
- package/tests/views/notifications.test.ts +13 -9
- package/tests/views/profile.test.ts +20 -18
- package/tests/views/thread.test.ts +54 -26
- package/tests/views/threadgating.test.ts +51 -19
- package/tests/views/timeline.test.ts +21 -13
- package/dist/api/com/atproto/admin/resolveModerationReports.d.ts +0 -3
- package/dist/api/com/atproto/admin/reverseModerationAction.d.ts +0 -3
- package/dist/api/com/atproto/admin/takeModerationAction.d.ts +0 -3
- package/dist/lexicon/types/com/atproto/admin/getModerationReport.d.ts +0 -29
- package/dist/lexicon/types/com/atproto/admin/resolveModerationReports.d.ts +0 -36
- package/dist/lexicon/types/com/atproto/admin/reverseModerationAction.d.ts +0 -36
- package/src/api/com/atproto/admin/getModerationAction.ts +0 -44
- package/src/api/com/atproto/admin/getModerationReport.ts +0 -43
- package/src/api/com/atproto/admin/resolveModerationReports.ts +0 -24
- package/src/api/com/atproto/admin/reverseModerationAction.ts +0 -115
- package/src/api/com/atproto/admin/takeModerationAction.ts +0 -156
- package/src/lexicon/types/com/atproto/admin/getModerationAction.ts +0 -41
- package/src/lexicon/types/com/atproto/admin/resolveModerationReports.ts +0 -49
- package/src/lexicon/types/com/atproto/admin/reverseModerationAction.ts +0 -49
- package/tests/admin/__snapshots__/get-moderation-action.test.ts.snap +0 -172
- package/tests/admin/__snapshots__/get-moderation-actions.test.ts.snap +0 -178
- package/tests/admin/__snapshots__/get-moderation-report.test.ts.snap +0 -177
- package/tests/admin/__snapshots__/get-moderation-reports.test.ts.snap +0 -307
- package/tests/admin/get-moderation-action.test.ts +0 -100
- package/tests/admin/get-moderation-actions.test.ts +0 -164
- package/tests/admin/get-moderation-report.test.ts +0 -100
- package/tests/admin/get-moderation-reports.test.ts +0 -332
- /package/dist/api/com/atproto/admin/{getModerationAction.d.ts → emitModerationEvent.d.ts} +0 -0
- /package/dist/api/com/atproto/admin/{getModerationActions.d.ts → getModerationEvent.d.ts} +0 -0
- /package/dist/api/com/atproto/admin/{getModerationReport.d.ts → queryModerationEvents.d.ts} +0 -0
- /package/dist/api/com/atproto/admin/{getModerationReports.d.ts → queryModerationStatuses.d.ts} +0 -0
|
@@ -6,27 +6,21 @@ import {
|
|
|
6
6
|
NotFoundPost,
|
|
7
7
|
ThreadViewPost,
|
|
8
8
|
isNotFoundPost,
|
|
9
|
-
isThreadViewPost,
|
|
10
9
|
} from '../../../../lexicon/types/app/bsky/feed/defs'
|
|
11
|
-
import { Record as PostRecord } from '../../../../lexicon/types/app/bsky/feed/post'
|
|
12
|
-
import { Record as ThreadgateRecord } from '../../../../lexicon/types/app/bsky/feed/threadgate'
|
|
13
10
|
import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getPostThread'
|
|
14
11
|
import AppContext from '../../../../context'
|
|
15
12
|
import {
|
|
16
13
|
FeedService,
|
|
17
14
|
FeedRow,
|
|
18
15
|
FeedHydrationState,
|
|
19
|
-
PostInfo,
|
|
20
16
|
} from '../../../../services/feed'
|
|
21
17
|
import {
|
|
22
18
|
getAncestorsAndSelfQb,
|
|
23
19
|
getDescendentsQb,
|
|
24
20
|
} from '../../../../services/util/post'
|
|
25
21
|
import { Database } from '../../../../db'
|
|
26
|
-
import DatabaseSchema from '../../../../db/database-schema'
|
|
27
22
|
import { setRepoRev } from '../../../util'
|
|
28
23
|
import { ActorInfoMap, ActorService } from '../../../../services/actor'
|
|
29
|
-
import { violatesThreadGate } from '../../../../services/feed/util'
|
|
30
24
|
import { createPipeline, noRules } from '../../../../pipeline'
|
|
31
25
|
|
|
32
26
|
export default function (server: Server, ctx: AppContext) {
|
|
@@ -80,21 +74,7 @@ const hydration = async (state: SkeletonState, ctx: Context) => {
|
|
|
80
74
|
} = state
|
|
81
75
|
const relevant = getRelevantIds(threadData)
|
|
82
76
|
const hydrated = await feedService.feedHydration({ ...relevant, viewer })
|
|
83
|
-
|
|
84
|
-
const anchorPostUri = threadData.post.postUri
|
|
85
|
-
const rootUri = threadData.post.replyRoot || anchorPostUri
|
|
86
|
-
const anchor = hydrated.posts[anchorPostUri]
|
|
87
|
-
const root = hydrated.posts[rootUri]
|
|
88
|
-
const gate = hydrated.threadgates[rootUri]?.record
|
|
89
|
-
const viewerCanReply = await checkViewerCanReply(
|
|
90
|
-
ctx.db.db,
|
|
91
|
-
anchor ?? null,
|
|
92
|
-
viewer,
|
|
93
|
-
new AtUri(rootUri).host,
|
|
94
|
-
(root?.record ?? null) as PostRecord | null,
|
|
95
|
-
gate ?? null,
|
|
96
|
-
)
|
|
97
|
-
return { ...state, ...hydrated, viewerCanReply }
|
|
77
|
+
return { ...state, ...hydrated }
|
|
98
78
|
}
|
|
99
79
|
|
|
100
80
|
const presentation = (state: HydrationState, ctx: Context) => {
|
|
@@ -103,16 +83,19 @@ const presentation = (state: HydrationState, ctx: Context) => {
|
|
|
103
83
|
const actors = actorService.views.profileBasicPresentation(
|
|
104
84
|
Object.keys(profiles),
|
|
105
85
|
state,
|
|
106
|
-
|
|
86
|
+
params.viewer,
|
|
87
|
+
)
|
|
88
|
+
const thread = composeThread(
|
|
89
|
+
state.threadData,
|
|
90
|
+
actors,
|
|
91
|
+
state,
|
|
92
|
+
ctx,
|
|
93
|
+
params.viewer,
|
|
107
94
|
)
|
|
108
|
-
const thread = composeThread(state.threadData, actors, state, ctx)
|
|
109
95
|
if (isNotFoundPost(thread)) {
|
|
110
96
|
// @TODO technically this could be returned as a NotFoundPost based on lexicon
|
|
111
97
|
throw new InvalidRequestError(`Post not found: ${params.uri}`, 'NotFound')
|
|
112
98
|
}
|
|
113
|
-
if (isThreadViewPost(thread) && params.viewer) {
|
|
114
|
-
thread.viewer = { canReply: state.viewerCanReply }
|
|
115
|
-
}
|
|
116
99
|
return { thread }
|
|
117
100
|
}
|
|
118
101
|
|
|
@@ -121,6 +104,7 @@ const composeThread = (
|
|
|
121
104
|
actors: ActorInfoMap,
|
|
122
105
|
state: HydrationState,
|
|
123
106
|
ctx: Context,
|
|
107
|
+
viewer: string | null,
|
|
124
108
|
) => {
|
|
125
109
|
const { feedService } = ctx
|
|
126
110
|
const { posts, threadgates, embeds, blocks, labels, lists } = state
|
|
@@ -133,6 +117,7 @@ const composeThread = (
|
|
|
133
117
|
embeds,
|
|
134
118
|
labels,
|
|
135
119
|
lists,
|
|
120
|
+
viewer,
|
|
136
121
|
)
|
|
137
122
|
|
|
138
123
|
// replies that are invalid due to reply-gating:
|
|
@@ -179,14 +164,14 @@ const composeThread = (
|
|
|
179
164
|
notFound: true,
|
|
180
165
|
}
|
|
181
166
|
} else {
|
|
182
|
-
parent = composeThread(threadData.parent, actors, state, ctx)
|
|
167
|
+
parent = composeThread(threadData.parent, actors, state, ctx, viewer)
|
|
183
168
|
}
|
|
184
169
|
}
|
|
185
170
|
|
|
186
171
|
let replies: (ThreadViewPost | NotFoundPost | BlockedPost)[] | undefined
|
|
187
172
|
if (threadData.replies && !badReply) {
|
|
188
173
|
replies = threadData.replies.flatMap((reply) => {
|
|
189
|
-
const thread = composeThread(reply, actors, state, ctx)
|
|
174
|
+
const thread = composeThread(reply, actors, state, ctx, viewer)
|
|
190
175
|
// e.g. don't bother including #postNotFound reply placeholders for takedowns. either way matches api contract.
|
|
191
176
|
const skip = []
|
|
192
177
|
return isNotFoundPost(thread) ? skip : thread
|
|
@@ -223,6 +208,7 @@ const getRelevantIds = (
|
|
|
223
208
|
if (thread.post.replyRoot) {
|
|
224
209
|
// ensure root is included for checking interactions
|
|
225
210
|
uris.add(thread.post.replyRoot)
|
|
211
|
+
dids.add(new AtUri(thread.post.replyRoot).hostname)
|
|
226
212
|
}
|
|
227
213
|
return { dids, uris }
|
|
228
214
|
}
|
|
@@ -317,28 +303,6 @@ const getChildrenData = (
|
|
|
317
303
|
}))
|
|
318
304
|
}
|
|
319
305
|
|
|
320
|
-
const checkViewerCanReply = async (
|
|
321
|
-
db: DatabaseSchema,
|
|
322
|
-
anchor: PostInfo | null,
|
|
323
|
-
viewer: string | null,
|
|
324
|
-
owner: string,
|
|
325
|
-
root: PostRecord | null,
|
|
326
|
-
threadgate: ThreadgateRecord | null,
|
|
327
|
-
) => {
|
|
328
|
-
if (!viewer) return false
|
|
329
|
-
// @TODO re-enable invalidReplyRoot check
|
|
330
|
-
// if (anchor?.invalidReplyRoot || anchor?.violatesThreadGate) return false
|
|
331
|
-
if (anchor?.violatesThreadGate) return false
|
|
332
|
-
const viewerViolatesThreadGate = await violatesThreadGate(
|
|
333
|
-
db,
|
|
334
|
-
viewer,
|
|
335
|
-
owner,
|
|
336
|
-
root,
|
|
337
|
-
threadgate,
|
|
338
|
-
)
|
|
339
|
-
return !viewerViolatesThreadGate
|
|
340
|
-
}
|
|
341
|
-
|
|
342
306
|
class ParentNotFoundError extends Error {
|
|
343
307
|
constructor(public uri: string) {
|
|
344
308
|
super(`Parent not found: ${uri}`)
|
|
@@ -364,7 +328,4 @@ type SkeletonState = {
|
|
|
364
328
|
threadData: PostThread
|
|
365
329
|
}
|
|
366
330
|
|
|
367
|
-
type HydrationState = SkeletonState &
|
|
368
|
-
FeedHydrationState & {
|
|
369
|
-
viewerCanReply: boolean
|
|
370
|
-
}
|
|
331
|
+
type HydrationState = SkeletonState & FeedHydrationState
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { dedupeStrs } from '@atproto/common'
|
|
2
|
-
import { AtUri } from '@atproto/syntax'
|
|
3
2
|
import { Server } from '../../../../lexicon'
|
|
4
3
|
import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getPosts'
|
|
5
4
|
import AppContext from '../../../../context'
|
|
6
5
|
import { Database } from '../../../../db'
|
|
7
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
FeedHydrationState,
|
|
8
|
+
FeedRow,
|
|
9
|
+
FeedService,
|
|
10
|
+
} from '../../../../services/feed'
|
|
8
11
|
import { createPipeline } from '../../../../pipeline'
|
|
9
12
|
import { ActorService } from '../../../../services/actor'
|
|
10
13
|
|
|
@@ -31,18 +34,18 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
31
34
|
})
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
const skeleton = async (params: Params) => {
|
|
35
|
-
|
|
37
|
+
const skeleton = async (params: Params, ctx: Context) => {
|
|
38
|
+
const deduped = dedupeStrs(params.uris)
|
|
39
|
+
const feedItems = await ctx.feedService.postUrisToFeedItems(deduped)
|
|
40
|
+
return { params, feedItems }
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
const hydration = async (state: SkeletonState, ctx: Context) => {
|
|
39
44
|
const { feedService } = ctx
|
|
40
|
-
const { params,
|
|
41
|
-
const
|
|
42
|
-
const dids = new Set<string>(postUris.map((uri) => new AtUri(uri).hostname))
|
|
45
|
+
const { params, feedItems } = state
|
|
46
|
+
const refs = feedService.feedItemRefs(feedItems)
|
|
43
47
|
const hydrated = await feedService.feedHydration({
|
|
44
|
-
|
|
45
|
-
dids,
|
|
48
|
+
...refs,
|
|
46
49
|
viewer: params.viewer,
|
|
47
50
|
})
|
|
48
51
|
return { ...state, ...hydrated }
|
|
@@ -50,32 +53,32 @@ const hydration = async (state: SkeletonState, ctx: Context) => {
|
|
|
50
53
|
|
|
51
54
|
const noBlocks = (state: HydrationState) => {
|
|
52
55
|
const { viewer } = state.params
|
|
53
|
-
state.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return !state.bam.block([viewer, post.creator])
|
|
56
|
+
state.feedItems = state.feedItems.filter((item) => {
|
|
57
|
+
if (!viewer) return true
|
|
58
|
+
return !state.bam.block([viewer, item.postAuthorDid])
|
|
57
59
|
})
|
|
58
60
|
return state
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
const presentation = (state: HydrationState, ctx: Context) => {
|
|
62
64
|
const { feedService, actorService } = ctx
|
|
63
|
-
const {
|
|
65
|
+
const { feedItems, profiles, params } = state
|
|
64
66
|
const SKIP = []
|
|
65
67
|
const actors = actorService.views.profileBasicPresentation(
|
|
66
68
|
Object.keys(profiles),
|
|
67
69
|
state,
|
|
68
|
-
|
|
70
|
+
params.viewer,
|
|
69
71
|
)
|
|
70
|
-
const postViews =
|
|
72
|
+
const postViews = feedItems.flatMap((item) => {
|
|
71
73
|
const postView = feedService.views.formatPostView(
|
|
72
|
-
|
|
74
|
+
item.postUri,
|
|
73
75
|
actors,
|
|
74
76
|
state.posts,
|
|
75
77
|
state.threadgates,
|
|
76
78
|
state.embeds,
|
|
77
79
|
state.labels,
|
|
78
80
|
state.lists,
|
|
81
|
+
params.viewer,
|
|
79
82
|
)
|
|
80
83
|
return postView ?? SKIP
|
|
81
84
|
})
|
|
@@ -92,7 +95,7 @@ type Params = QueryParams & { viewer: string | null }
|
|
|
92
95
|
|
|
93
96
|
type SkeletonState = {
|
|
94
97
|
params: Params
|
|
95
|
-
|
|
98
|
+
feedItems: FeedRow[]
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
type HydrationState = SkeletonState & FeedHydrationState
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { mapDefined } from '@atproto/common'
|
|
1
2
|
import { Server } from '../../../../lexicon'
|
|
2
3
|
import AppContext from '../../../../context'
|
|
3
4
|
|
|
@@ -23,7 +24,7 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
23
24
|
const creators = genList.map((gen) => gen.creator)
|
|
24
25
|
const profiles = await actorService.views.profilesBasic(creators, viewer)
|
|
25
26
|
|
|
26
|
-
const feedViews = genList
|
|
27
|
+
const feedViews = mapDefined(genList, (gen) =>
|
|
27
28
|
feedService.views.formatFeedGeneratorView(gen, profiles),
|
|
28
29
|
)
|
|
29
30
|
|
|
@@ -146,9 +146,7 @@ const noBlocksOrMutes = (state: HydrationState): HydrationState => {
|
|
|
146
146
|
const presentation = (state: HydrationState, ctx: Context) => {
|
|
147
147
|
const { feedService } = ctx
|
|
148
148
|
const { feedItems, cursor, params } = state
|
|
149
|
-
const feed = feedService.views.formatFeed(feedItems, state,
|
|
150
|
-
viewer: params.viewer,
|
|
151
|
-
})
|
|
149
|
+
const feed = feedService.views.formatFeed(feedItems, state, params.viewer)
|
|
152
150
|
return { feed, cursor }
|
|
153
151
|
}
|
|
154
152
|
|
|
@@ -2,11 +2,14 @@ import AppContext from '../../../../context'
|
|
|
2
2
|
import { Server } from '../../../../lexicon'
|
|
3
3
|
import { InvalidRequestError } from '@atproto/xrpc-server'
|
|
4
4
|
import AtpAgent from '@atproto/api'
|
|
5
|
-
import { AtUri } from '@atproto/syntax'
|
|
6
5
|
import { mapDefined } from '@atproto/common'
|
|
7
6
|
import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/searchPosts'
|
|
8
7
|
import { Database } from '../../../../db'
|
|
9
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
FeedHydrationState,
|
|
10
|
+
FeedRow,
|
|
11
|
+
FeedService,
|
|
12
|
+
} from '../../../../services/feed'
|
|
10
13
|
import { ActorService } from '../../../../services/actor'
|
|
11
14
|
import { createPipeline } from '../../../../pipeline'
|
|
12
15
|
|
|
@@ -51,9 +54,11 @@ const skeleton = async (
|
|
|
51
54
|
cursor: params.cursor,
|
|
52
55
|
limit: params.limit,
|
|
53
56
|
})
|
|
57
|
+
const postUris = res.data.posts.map((a) => a.uri)
|
|
58
|
+
const feedItems = await ctx.feedService.postUrisToFeedItems(postUris)
|
|
54
59
|
return {
|
|
55
60
|
params,
|
|
56
|
-
|
|
61
|
+
feedItems,
|
|
57
62
|
cursor: res.data.cursor,
|
|
58
63
|
hitsTotal: res.data.hitsTotal,
|
|
59
64
|
}
|
|
@@ -64,12 +69,10 @@ const hydration = async (
|
|
|
64
69
|
ctx: Context,
|
|
65
70
|
): Promise<HydrationState> => {
|
|
66
71
|
const { feedService } = ctx
|
|
67
|
-
const { params,
|
|
68
|
-
const
|
|
69
|
-
const dids = new Set<string>(postUris.map((uri) => new AtUri(uri).hostname))
|
|
72
|
+
const { params, feedItems } = state
|
|
73
|
+
const refs = feedService.feedItemRefs(feedItems)
|
|
70
74
|
const hydrated = await feedService.feedHydration({
|
|
71
|
-
|
|
72
|
-
dids,
|
|
75
|
+
...refs,
|
|
73
76
|
viewer: params.viewer,
|
|
74
77
|
})
|
|
75
78
|
return { ...state, ...hydrated }
|
|
@@ -77,32 +80,32 @@ const hydration = async (
|
|
|
77
80
|
|
|
78
81
|
const noBlocks = (state: HydrationState): HydrationState => {
|
|
79
82
|
const { viewer } = state.params
|
|
80
|
-
state.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return !state.bam.block([viewer, post.creator])
|
|
83
|
+
state.feedItems = state.feedItems.filter((item) => {
|
|
84
|
+
if (!viewer) return true
|
|
85
|
+
return !state.bam.block([viewer, item.postAuthorDid])
|
|
84
86
|
})
|
|
85
87
|
return state
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
const presentation = (state: HydrationState, ctx: Context) => {
|
|
89
91
|
const { feedService, actorService } = ctx
|
|
90
|
-
const {
|
|
92
|
+
const { feedItems, profiles, params } = state
|
|
91
93
|
const actors = actorService.views.profileBasicPresentation(
|
|
92
94
|
Object.keys(profiles),
|
|
93
95
|
state,
|
|
94
|
-
|
|
96
|
+
params.viewer,
|
|
95
97
|
)
|
|
96
98
|
|
|
97
|
-
const postViews = mapDefined(
|
|
99
|
+
const postViews = mapDefined(feedItems, (item) =>
|
|
98
100
|
feedService.views.formatPostView(
|
|
99
|
-
|
|
101
|
+
item.postUri,
|
|
100
102
|
actors,
|
|
101
103
|
state.posts,
|
|
102
104
|
state.threadgates,
|
|
103
105
|
state.embeds,
|
|
104
106
|
state.labels,
|
|
105
107
|
state.lists,
|
|
108
|
+
params.viewer,
|
|
106
109
|
),
|
|
107
110
|
)
|
|
108
111
|
return { posts: postViews, cursor: state.cursor, hitsTotal: state.hitsTotal }
|
|
@@ -119,7 +122,7 @@ type Params = QueryParams & { viewer: string | null }
|
|
|
119
122
|
|
|
120
123
|
type SkeletonState = {
|
|
121
124
|
params: Params
|
|
122
|
-
|
|
125
|
+
feedItems: FeedRow[]
|
|
123
126
|
hitsTotal?: number
|
|
124
127
|
cursor?: string
|
|
125
128
|
}
|
|
@@ -91,17 +91,20 @@ const presentation = (state: HydrationState, ctx: Context) => {
|
|
|
91
91
|
const actors = actorService.views.profilePresentation(
|
|
92
92
|
Object.keys(profileState.profiles),
|
|
93
93
|
profileState,
|
|
94
|
-
|
|
94
|
+
params.viewer,
|
|
95
95
|
)
|
|
96
96
|
const creator = actors[list.creator]
|
|
97
97
|
if (!creator) {
|
|
98
98
|
throw new InvalidRequestError(`Actor not found: ${list.handle}`)
|
|
99
99
|
}
|
|
100
100
|
const listView = graphService.formatListView(list, actors)
|
|
101
|
+
if (!listView) {
|
|
102
|
+
throw new InvalidRequestError('List not found')
|
|
103
|
+
}
|
|
101
104
|
const items = mapDefined(listItems, (item) => {
|
|
102
105
|
const subject = actors[item.did]
|
|
103
106
|
if (!subject) return
|
|
104
|
-
return { subject }
|
|
107
|
+
return { uri: item.uri, subject }
|
|
105
108
|
})
|
|
106
109
|
return { list: listView, items, cursor }
|
|
107
110
|
}
|
|
@@ -119,7 +122,7 @@ type Params = QueryParams & {
|
|
|
119
122
|
type SkeletonState = {
|
|
120
123
|
params: Params
|
|
121
124
|
list: Actor & ListInfo
|
|
122
|
-
listItems: (Actor & { cid: string; sortAt: string })[]
|
|
125
|
+
listItems: (Actor & { uri: string; cid: string; sortAt: string })[]
|
|
123
126
|
cursor?: string
|
|
124
127
|
}
|
|
125
128
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { mapDefined } from '@atproto/common'
|
|
1
2
|
import { Server } from '../../../../lexicon'
|
|
2
3
|
import { QueryParams } from '../../../../lexicon/types/app/bsky/graph/getListBlocks'
|
|
3
4
|
import { paginate, TimeCidKeyset } from '../../../../db/pagination'
|
|
@@ -87,9 +88,9 @@ const presentation = (state: HydrationState, ctx: Context) => {
|
|
|
87
88
|
const actors = actorService.views.profilePresentation(
|
|
88
89
|
Object.keys(profileState.profiles),
|
|
89
90
|
profileState,
|
|
90
|
-
|
|
91
|
+
params.viewer,
|
|
91
92
|
)
|
|
92
|
-
const lists = listInfos
|
|
93
|
+
const lists = mapDefined(listInfos, (list) =>
|
|
93
94
|
graphService.formatListView(list, actors),
|
|
94
95
|
)
|
|
95
96
|
return { lists, cursor }
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { mapDefined } from '@atproto/common'
|
|
1
2
|
import { Server } from '../../../../lexicon'
|
|
2
3
|
import { paginate, TimeCidKeyset } from '../../../../db/pagination'
|
|
3
4
|
import AppContext from '../../../../context'
|
|
@@ -34,7 +35,7 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
34
35
|
const actorService = ctx.services.actor(db)
|
|
35
36
|
const profiles = await actorService.views.profiles(listsRes, requester)
|
|
36
37
|
|
|
37
|
-
const lists = listsRes
|
|
38
|
+
const lists = mapDefined(listsRes, (row) =>
|
|
38
39
|
graphService.formatListView(row, profiles),
|
|
39
40
|
)
|
|
40
41
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { mapDefined } from '@atproto/common'
|
|
1
2
|
import { InvalidRequestError } from '@atproto/xrpc-server'
|
|
2
3
|
import { Server } from '../../../../lexicon'
|
|
3
4
|
import { paginate, TimeCidKeyset } from '../../../../db/pagination'
|
|
@@ -39,7 +40,7 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
39
40
|
throw new InvalidRequestError(`Actor not found: ${actor}`)
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
const lists = listsRes
|
|
43
|
+
const lists = mapDefined(listsRes, (row) =>
|
|
43
44
|
graphService.formatListView(row, profiles),
|
|
44
45
|
)
|
|
45
46
|
|
|
@@ -57,7 +57,9 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
57
57
|
const gen = genInfos[row.uri]
|
|
58
58
|
if (!gen) continue
|
|
59
59
|
const view = feedService.views.formatFeedGeneratorView(gen, profiles)
|
|
60
|
-
|
|
60
|
+
if (view) {
|
|
61
|
+
genViews.push(view)
|
|
62
|
+
}
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
return {
|
package/src/api/blob-resolver.ts
CHANGED
|
@@ -6,11 +6,11 @@ import { CID } from 'multiformats/cid'
|
|
|
6
6
|
import { ensureValidDid } from '@atproto/syntax'
|
|
7
7
|
import { forwardStreamErrors, VerifyCidTransform } from '@atproto/common'
|
|
8
8
|
import { IdResolver, DidNotFoundError } from '@atproto/identity'
|
|
9
|
-
import { TAKEDOWN } from '../lexicon/types/com/atproto/admin/defs'
|
|
10
9
|
import AppContext from '../context'
|
|
11
10
|
import { httpLogger as log } from '../logger'
|
|
12
11
|
import { retryHttp } from '../util/retry'
|
|
13
12
|
import { Database } from '../db'
|
|
13
|
+
import { sql } from 'kysely'
|
|
14
14
|
|
|
15
15
|
// Resolve and verify blob from its origin host
|
|
16
16
|
|
|
@@ -84,19 +84,14 @@ export async function resolveBlob(
|
|
|
84
84
|
idResolver: IdResolver,
|
|
85
85
|
) {
|
|
86
86
|
const cidStr = cid.toString()
|
|
87
|
+
|
|
87
88
|
const [{ pds }, takedown] = await Promise.all([
|
|
88
89
|
idResolver.did.resolveAtprotoData(did), // @TODO cache did info
|
|
89
90
|
db.db
|
|
90
|
-
.selectFrom('
|
|
91
|
-
.select('
|
|
92
|
-
.
|
|
93
|
-
|
|
94
|
-
'moderation_action.id',
|
|
95
|
-
'moderation_action_subject_blob.actionId',
|
|
96
|
-
)
|
|
97
|
-
.where('cid', '=', cidStr)
|
|
98
|
-
.where('action', '=', TAKEDOWN)
|
|
99
|
-
.where('reversedAt', 'is', null)
|
|
91
|
+
.selectFrom('moderation_subject_status')
|
|
92
|
+
.select('id')
|
|
93
|
+
.where('blobCids', '@>', sql`CAST(${JSON.stringify([cidStr])} AS JSONB)`)
|
|
94
|
+
.where('takendown', 'is', true)
|
|
100
95
|
.executeTakeFirst(),
|
|
101
96
|
])
|
|
102
97
|
if (takedown) {
|