@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.
Files changed (170) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/api/com/atproto/moderation/util.d.ts +4 -3
  3. package/dist/context.d.ts +15 -0
  4. package/dist/db/index.js +26 -1
  5. package/dist/db/index.js.map +3 -3
  6. package/dist/db/migrations/20231003T202833377Z-create-moderation-subject-status.d.ts +3 -0
  7. package/dist/db/migrations/index.d.ts +1 -0
  8. package/dist/db/pagination.d.ts +2 -1
  9. package/dist/db/{periodic-moderation-action-reversal.d.ts → periodic-moderation-event-reversal.d.ts} +3 -5
  10. package/dist/db/tables/moderation.d.ts +24 -34
  11. package/dist/feed-gen/types.d.ts +1 -1
  12. package/dist/index.d.ts +2 -1
  13. package/dist/index.js +2750 -2121
  14. package/dist/index.js.map +3 -3
  15. package/dist/lexicon/index.d.ts +11 -18
  16. package/dist/lexicon/lexicons.d.ts +414 -399
  17. package/dist/lexicon/types/app/bsky/feed/defs.d.ts +1 -7
  18. package/dist/lexicon/types/app/bsky/graph/defs.d.ts +1 -0
  19. package/dist/lexicon/types/com/atproto/admin/defs.d.ts +114 -48
  20. package/dist/lexicon/types/com/atproto/admin/{takeModerationAction.d.ts → emitModerationEvent.d.ts} +5 -6
  21. package/dist/lexicon/types/com/atproto/admin/{getModerationAction.d.ts → getModerationEvent.d.ts} +1 -1
  22. package/dist/lexicon/types/com/atproto/admin/{getModerationActions.d.ts → queryModerationEvents.d.ts} +5 -1
  23. package/dist/lexicon/types/com/atproto/admin/{getModerationReports.d.ts → queryModerationStatuses.d.ts} +12 -6
  24. package/dist/lexicon/types/com/atproto/admin/sendEmail.d.ts +1 -0
  25. package/dist/migrate-moderation-data.d.ts +1 -0
  26. package/dist/services/actor/views.d.ts +2 -5
  27. package/dist/services/feed/index.d.ts +1 -0
  28. package/dist/services/feed/util.d.ts +9 -1
  29. package/dist/services/feed/views.d.ts +6 -17
  30. package/dist/services/graph/index.d.ts +5 -29
  31. package/dist/services/graph/types.d.ts +1 -0
  32. package/dist/services/moderation/index.d.ts +135 -72
  33. package/dist/services/moderation/pagination.d.ts +36 -0
  34. package/dist/services/moderation/status.d.ts +13 -0
  35. package/dist/services/moderation/types.d.ts +35 -0
  36. package/dist/services/moderation/views.d.ts +18 -14
  37. package/dist/util/debug.d.ts +1 -1
  38. package/package.json +11 -11
  39. package/src/api/app/bsky/feed/getActorFeeds.ts +2 -1
  40. package/src/api/app/bsky/feed/getActorLikes.ts +1 -3
  41. package/src/api/app/bsky/feed/getAuthorFeed.ts +1 -3
  42. package/src/api/app/bsky/feed/getFeed.ts +9 -9
  43. package/src/api/app/bsky/feed/getFeedGenerator.ts +3 -0
  44. package/src/api/app/bsky/feed/getFeedGenerators.ts +2 -1
  45. package/src/api/app/bsky/feed/getListFeed.ts +1 -3
  46. package/src/api/app/bsky/feed/getPostThread.ts +15 -54
  47. package/src/api/app/bsky/feed/getPosts.ts +21 -18
  48. package/src/api/app/bsky/feed/getSuggestedFeeds.ts +2 -1
  49. package/src/api/app/bsky/feed/getTimeline.ts +1 -3
  50. package/src/api/app/bsky/feed/searchPosts.ts +20 -17
  51. package/src/api/app/bsky/graph/getList.ts +6 -3
  52. package/src/api/app/bsky/graph/getListBlocks.ts +3 -2
  53. package/src/api/app/bsky/graph/getListMutes.ts +2 -1
  54. package/src/api/app/bsky/graph/getLists.ts +2 -1
  55. package/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +3 -1
  56. package/src/api/blob-resolver.ts +6 -11
  57. package/src/api/com/atproto/admin/emitModerationEvent.ts +220 -0
  58. package/src/api/com/atproto/admin/{getModerationActions.ts → getModerationEvent.ts} +5 -11
  59. package/src/api/com/atproto/admin/getRecord.ts +1 -0
  60. package/src/api/com/atproto/admin/{getModerationReports.ts → queryModerationEvents.ts} +13 -16
  61. package/src/api/com/atproto/admin/queryModerationStatuses.ts +55 -0
  62. package/src/api/com/atproto/moderation/createReport.ts +9 -7
  63. package/src/api/com/atproto/moderation/util.ts +38 -20
  64. package/src/api/index.ts +8 -14
  65. package/src/auth.ts +29 -21
  66. package/src/auto-moderator/index.ts +26 -19
  67. package/src/context.ts +4 -0
  68. package/src/db/migrations/20231003T202833377Z-create-moderation-subject-status.ts +123 -0
  69. package/src/db/migrations/index.ts +1 -0
  70. package/src/db/pagination.ts +26 -3
  71. package/src/db/{periodic-moderation-action-reversal.ts → periodic-moderation-event-reversal.ts} +50 -46
  72. package/src/db/tables/moderation.ts +35 -52
  73. package/src/feed-gen/best-of-follows.ts +6 -3
  74. package/src/feed-gen/bsky-team.ts +1 -1
  75. package/src/feed-gen/hot-classic.ts +1 -1
  76. package/src/feed-gen/mutuals.ts +6 -2
  77. package/src/feed-gen/types.ts +1 -1
  78. package/src/feed-gen/whats-hot.ts +1 -1
  79. package/src/feed-gen/with-friends.ts +7 -3
  80. package/src/index.ts +2 -1
  81. package/src/lexicon/index.ts +30 -67
  82. package/src/lexicon/lexicons.ts +526 -491
  83. package/src/lexicon/types/app/bsky/feed/defs.ts +1 -18
  84. package/src/lexicon/types/app/bsky/graph/defs.ts +1 -0
  85. package/src/lexicon/types/com/atproto/admin/defs.ts +276 -84
  86. package/src/lexicon/types/com/atproto/admin/{takeModerationAction.ts → emitModerationEvent.ts} +13 -11
  87. package/src/lexicon/types/com/atproto/admin/{getModerationReport.ts → getModerationEvent.ts} +1 -1
  88. package/src/lexicon/types/com/atproto/admin/{getModerationActions.ts → queryModerationEvents.ts} +8 -1
  89. package/src/lexicon/types/com/atproto/admin/{getModerationReports.ts → queryModerationStatuses.ts} +21 -14
  90. package/src/lexicon/types/com/atproto/admin/sendEmail.ts +1 -0
  91. package/src/migrate-moderation-data.ts +414 -0
  92. package/src/services/actor/views.ts +5 -14
  93. package/src/services/feed/index.ts +26 -7
  94. package/src/services/feed/util.ts +47 -19
  95. package/src/services/feed/views.ts +68 -4
  96. package/src/services/graph/index.ts +21 -3
  97. package/src/services/graph/types.ts +1 -0
  98. package/src/services/indexing/plugins/block.ts +2 -3
  99. package/src/services/indexing/plugins/feed-generator.ts +2 -3
  100. package/src/services/indexing/plugins/follow.ts +2 -3
  101. package/src/services/indexing/plugins/like.ts +2 -3
  102. package/src/services/indexing/plugins/list-block.ts +2 -3
  103. package/src/services/indexing/plugins/list-item.ts +2 -3
  104. package/src/services/indexing/plugins/list.ts +2 -3
  105. package/src/services/indexing/plugins/post.ts +3 -4
  106. package/src/services/indexing/plugins/repost.ts +2 -3
  107. package/src/services/indexing/plugins/thread-gate.ts +2 -3
  108. package/src/services/label/index.ts +2 -3
  109. package/src/services/moderation/index.ts +380 -395
  110. package/src/services/moderation/pagination.ts +96 -0
  111. package/src/services/moderation/status.ts +244 -0
  112. package/src/services/moderation/types.ts +49 -0
  113. package/src/services/moderation/views.ts +278 -329
  114. package/src/util/debug.ts +2 -2
  115. package/tests/__snapshots__/feed-generation.test.ts.snap +322 -6
  116. package/tests/__snapshots__/indexing.test.ts.snap +0 -6
  117. package/tests/admin/__snapshots__/get-record.test.ts.snap +30 -132
  118. package/tests/admin/__snapshots__/get-repo.test.ts.snap +14 -60
  119. package/tests/admin/__snapshots__/moderation-events.test.ts.snap +146 -0
  120. package/tests/admin/__snapshots__/moderation-statuses.test.ts.snap +64 -0
  121. package/tests/admin/__snapshots__/moderation.test.ts.snap +0 -125
  122. package/tests/admin/get-record.test.ts +5 -9
  123. package/tests/admin/get-repo.test.ts +5 -9
  124. package/tests/admin/moderation-events.test.ts +221 -0
  125. package/tests/admin/moderation-statuses.test.ts +145 -0
  126. package/tests/admin/moderation.test.ts +512 -860
  127. package/tests/admin/repo-search.test.ts +2 -3
  128. package/tests/auto-moderator/fuzzy-matcher.test.ts +2 -1
  129. package/tests/auto-moderator/takedowns.test.ts +45 -18
  130. package/tests/feed-generation.test.ts +57 -9
  131. package/tests/views/__snapshots__/block-lists.test.ts.snap +3 -9
  132. package/tests/views/__snapshots__/blocks.test.ts.snap +0 -9
  133. package/tests/views/__snapshots__/mute-lists.test.ts.snap +5 -5
  134. package/tests/views/__snapshots__/mutes.test.ts.snap +0 -3
  135. package/tests/views/__snapshots__/thread.test.ts.snap +0 -30
  136. package/tests/views/actor-search.test.ts +2 -3
  137. package/tests/views/author-feed.test.ts +42 -36
  138. package/tests/views/follows.test.ts +40 -35
  139. package/tests/views/list-feed.test.ts +17 -9
  140. package/tests/views/notifications.test.ts +13 -9
  141. package/tests/views/profile.test.ts +20 -18
  142. package/tests/views/thread.test.ts +54 -26
  143. package/tests/views/threadgating.test.ts +51 -19
  144. package/tests/views/timeline.test.ts +21 -13
  145. package/dist/api/com/atproto/admin/resolveModerationReports.d.ts +0 -3
  146. package/dist/api/com/atproto/admin/reverseModerationAction.d.ts +0 -3
  147. package/dist/api/com/atproto/admin/takeModerationAction.d.ts +0 -3
  148. package/dist/lexicon/types/com/atproto/admin/getModerationReport.d.ts +0 -29
  149. package/dist/lexicon/types/com/atproto/admin/resolveModerationReports.d.ts +0 -36
  150. package/dist/lexicon/types/com/atproto/admin/reverseModerationAction.d.ts +0 -36
  151. package/src/api/com/atproto/admin/getModerationAction.ts +0 -44
  152. package/src/api/com/atproto/admin/getModerationReport.ts +0 -43
  153. package/src/api/com/atproto/admin/resolveModerationReports.ts +0 -24
  154. package/src/api/com/atproto/admin/reverseModerationAction.ts +0 -115
  155. package/src/api/com/atproto/admin/takeModerationAction.ts +0 -156
  156. package/src/lexicon/types/com/atproto/admin/getModerationAction.ts +0 -41
  157. package/src/lexicon/types/com/atproto/admin/resolveModerationReports.ts +0 -49
  158. package/src/lexicon/types/com/atproto/admin/reverseModerationAction.ts +0 -49
  159. package/tests/admin/__snapshots__/get-moderation-action.test.ts.snap +0 -172
  160. package/tests/admin/__snapshots__/get-moderation-actions.test.ts.snap +0 -178
  161. package/tests/admin/__snapshots__/get-moderation-report.test.ts.snap +0 -177
  162. package/tests/admin/__snapshots__/get-moderation-reports.test.ts.snap +0 -307
  163. package/tests/admin/get-moderation-action.test.ts +0 -100
  164. package/tests/admin/get-moderation-actions.test.ts +0 -164
  165. package/tests/admin/get-moderation-report.test.ts +0 -100
  166. package/tests/admin/get-moderation-reports.test.ts +0 -332
  167. /package/dist/api/com/atproto/admin/{getModerationAction.d.ts → emitModerationEvent.d.ts} +0 -0
  168. /package/dist/api/com/atproto/admin/{getModerationActions.d.ts → getModerationEvent.d.ts} +0 -0
  169. /package/dist/api/com/atproto/admin/{getModerationReport.d.ts → queryModerationEvents.d.ts} +0 -0
  170. /package/dist/api/com/atproto/admin/{getModerationReports.d.ts → queryModerationStatuses.d.ts} +0 -0
@@ -1,6 +1,5 @@
1
1
  import { SeedClient, TestNetwork } from '@atproto/dev-env'
2
2
  import AtpAgent from '@atproto/api'
3
- import { TAKEDOWN } from '@atproto/api/src/client/types/com/atproto/admin/defs'
4
3
  import { paginateAll } from '../_util'
5
4
  import usersBulkSeed from '../seeds/users-bulk'
6
5
 
@@ -25,8 +24,8 @@ describe('admin repo search view', () => {
25
24
  })
26
25
 
27
26
  beforeAll(async () => {
28
- await sc.takeModerationAction({
29
- action: TAKEDOWN,
27
+ await sc.emitModerationEvent({
28
+ event: { $type: 'com.atproto.admin.defs#modEventTakedown' },
30
29
  subject: {
31
30
  $type: 'com.atproto.admin.defs#repoRef',
32
31
  did: sc.dids['cara-wiegand69.test'],
@@ -37,7 +37,8 @@ describe('fuzzy matcher', () => {
37
37
  const getAllReports = () => {
38
38
  return network.bsky.ctx.db
39
39
  .getPrimary()
40
- .db.selectFrom('moderation_report')
40
+ .db.selectFrom('moderation_event')
41
+ .where('action', '=', 'com.atproto.admin.defs#modEventReport')
41
42
  .selectAll()
42
43
  .orderBy('id', 'asc')
43
44
  .execute()
@@ -77,28 +77,41 @@ describe('takedowner', () => {
77
77
  const post = await sc.post(alice, 'blah', undefined, [goodBlob, badBlob1])
78
78
  await network.processAll()
79
79
  await autoMod.processAll()
80
- const modAction = await ctx.db.db
81
- .selectFrom('moderation_action')
82
- .where('subjectUri', '=', post.ref.uriStr)
83
- .select(['action', 'id'])
84
- .executeTakeFirst()
85
- if (!modAction) {
80
+ const [modStatus, takedownEvent] = await Promise.all([
81
+ ctx.db.db
82
+ .selectFrom('moderation_subject_status')
83
+ .where('did', '=', alice)
84
+ .where(
85
+ 'recordPath',
86
+ '=',
87
+ `${post.ref.uri.collection}/${post.ref.uri.rkey}`,
88
+ )
89
+ .select(['takendown', 'id'])
90
+ .executeTakeFirst(),
91
+ ctx.db.db
92
+ .selectFrom('moderation_event')
93
+ .where('subjectDid', '=', alice)
94
+ .where('action', '=', 'com.atproto.admin.defs#modEventTakedown')
95
+ .selectAll()
96
+ .executeTakeFirst(),
97
+ ])
98
+ if (!modStatus || !takedownEvent) {
86
99
  throw new Error('expected mod action')
87
100
  }
88
- expect(modAction.action).toEqual('com.atproto.admin.defs#takedown')
101
+ expect(modStatus.takendown).toEqual(true)
89
102
  const record = await ctx.db.db
90
103
  .selectFrom('record')
91
104
  .where('uri', '=', post.ref.uriStr)
92
105
  .select('takedownId')
93
106
  .executeTakeFirst()
94
- expect(record?.takedownId).toEqual(modAction.id)
107
+ expect(record?.takedownId).toBeGreaterThan(0)
95
108
 
96
109
  const recordPds = await network.pds.ctx.db.db
97
110
  .selectFrom('record')
98
111
  .where('uri', '=', post.ref.uriStr)
99
112
  .select('takedownRef')
100
113
  .executeTakeFirst()
101
- expect(recordPds?.takedownRef).toEqual(modAction.id.toString())
114
+ expect(recordPds?.takedownRef).toEqual(takedownEvent.id.toString())
102
115
 
103
116
  expect(testInvalidator.invalidated.length).toBe(1)
104
117
  expect(testInvalidator.invalidated[0].subject).toBe(
@@ -119,28 +132,42 @@ describe('takedowner', () => {
119
132
  { headers: sc.getHeaders(alice), encoding: 'application/json' },
120
133
  )
121
134
  await network.processAll()
122
- const modAction = await ctx.db.db
123
- .selectFrom('moderation_action')
124
- .where('subjectUri', '=', res.data.uri)
125
- .select(['action', 'id'])
126
- .executeTakeFirst()
127
- if (!modAction) {
135
+ const [modStatus, takedownEvent] = await Promise.all([
136
+ ctx.db.db
137
+ .selectFrom('moderation_subject_status')
138
+ .where('did', '=', alice)
139
+ .where('recordPath', '=', `${ids.AppBskyActorProfile}/self`)
140
+ .select(['takendown', 'id'])
141
+ .executeTakeFirst(),
142
+ ctx.db.db
143
+ .selectFrom('moderation_event')
144
+ .where('subjectDid', '=', alice)
145
+ .where(
146
+ 'subjectUri',
147
+ '=',
148
+ AtUri.make(alice, ids.AppBskyActorProfile, 'self').toString(),
149
+ )
150
+ .where('action', '=', 'com.atproto.admin.defs#modEventTakedown')
151
+ .selectAll()
152
+ .executeTakeFirst(),
153
+ ])
154
+ if (!modStatus || !takedownEvent) {
128
155
  throw new Error('expected mod action')
129
156
  }
130
- expect(modAction.action).toEqual('com.atproto.admin.defs#takedown')
157
+ expect(modStatus.takendown).toEqual(true)
131
158
  const record = await ctx.db.db
132
159
  .selectFrom('record')
133
160
  .where('uri', '=', res.data.uri)
134
161
  .select('takedownId')
135
162
  .executeTakeFirst()
136
- expect(record?.takedownId).toEqual(modAction.id)
163
+ expect(record?.takedownId).toBeGreaterThan(0)
137
164
 
138
165
  const recordPds = await network.pds.ctx.db.db
139
166
  .selectFrom('record')
140
167
  .where('uri', '=', res.data.uri)
141
168
  .select('takedownRef')
142
169
  .executeTakeFirst()
143
- expect(recordPds?.takedownRef).toEqual(modAction.id.toString())
170
+ expect(recordPds?.takedownRef).toEqual(takedownEvent.id.toString())
144
171
 
145
172
  expect(testInvalidator.invalidated.length).toBe(2)
146
173
  expect(testInvalidator.invalidated[1].subject).toBe(
@@ -9,7 +9,6 @@ import {
9
9
  import { Handler as SkeletonHandler } from '../src/lexicon/types/app/bsky/feed/getFeedSkeleton'
10
10
  import { GeneratorView } from '@atproto/api/src/client/types/app/bsky/feed/defs'
11
11
  import { UnknownFeedError } from '@atproto/api/src/client/types/app/bsky/feed/getFeed'
12
- import { TAKEDOWN } from '@atproto/api/src/client/types/com/atproto/admin/defs'
13
12
  import { ids } from '../src/lexicon/lexicons'
14
13
  import {
15
14
  FeedViewPost,
@@ -17,6 +16,9 @@ import {
17
16
  } from '../src/lexicon/types/app/bsky/feed/defs'
18
17
  import basicSeed from './seeds/basic'
19
18
  import { forSnapshot, paginateAll } from './_util'
19
+ import { AuthRequiredError } from '@atproto/xrpc-server'
20
+ import assert from 'assert'
21
+ import { XRPCError } from '@atproto/xrpc'
20
22
 
21
23
  describe('feed generation', () => {
22
24
  let network: TestNetwork
@@ -33,6 +35,7 @@ describe('feed generation', () => {
33
35
  let feedUriBadPagination: string
34
36
  let feedUriPrime: string // Taken-down
35
37
  let feedUriPrimeRef: RecordRef
38
+ let feedUriNeedsAuth: string
36
39
 
37
40
  beforeAll(async () => {
38
41
  network = await TestNetwork.create({
@@ -52,11 +55,17 @@ describe('feed generation', () => {
52
55
  )
53
56
  const evenUri = AtUri.make(alice, 'app.bsky.feed.generator', 'even')
54
57
  const primeUri = AtUri.make(alice, 'app.bsky.feed.generator', 'prime')
58
+ const needsAuthUri = AtUri.make(
59
+ alice,
60
+ 'app.bsky.feed.generator',
61
+ 'needs-auth',
62
+ )
55
63
  gen = await network.createFeedGen({
56
64
  [allUri.toString()]: feedGenHandler('all'),
57
65
  [evenUri.toString()]: feedGenHandler('even'),
58
66
  [feedUriBadPagination.toString()]: feedGenHandler('bad-pagination'),
59
67
  [primeUri.toString()]: feedGenHandler('prime'),
68
+ [needsAuthUri.toString()]: feedGenHandler('needs-auth'),
60
69
  })
61
70
 
62
71
  const feedSuggestions = [
@@ -137,10 +146,20 @@ describe('feed generation', () => {
137
146
  },
138
147
  sc.getHeaders(alice),
139
148
  )
149
+ const needsAuth = await pdsAgent.api.app.bsky.feed.generator.create(
150
+ { repo: alice, rkey: 'needs-auth' },
151
+ {
152
+ did: gen.did,
153
+ displayName: 'Needs Auth',
154
+ description: 'Provides all feed candidates when authed',
155
+ createdAt: new Date().toISOString(),
156
+ },
157
+ sc.getHeaders(alice),
158
+ )
140
159
  await network.processAll()
141
- await agent.api.com.atproto.admin.takeModerationAction(
160
+ await agent.api.com.atproto.admin.emitModerationEvent(
142
161
  {
143
- action: TAKEDOWN,
162
+ event: { $type: 'com.atproto.admin.defs#modEventTakedown' },
144
163
  subject: {
145
164
  $type: 'com.atproto.repo.strongRef',
146
165
  uri: prime.uri,
@@ -161,6 +180,7 @@ describe('feed generation', () => {
161
180
  feedUriBadPagination = badPagination.uri
162
181
  feedUriPrime = prime.uri
163
182
  feedUriPrimeRef = new RecordRef(prime.uri, prime.cid)
183
+ feedUriNeedsAuth = needsAuth.uri
164
184
  })
165
185
 
166
186
  it('feed gen records can be updated', async () => {
@@ -198,11 +218,12 @@ describe('feed generation', () => {
198
218
 
199
219
  const paginatedAll: GeneratorView[] = results(await paginateAll(paginator))
200
220
 
201
- expect(paginatedAll.length).toEqual(4)
221
+ expect(paginatedAll.length).toEqual(5)
202
222
  expect(paginatedAll[0].uri).toEqual(feedUriOdd)
203
- expect(paginatedAll[1].uri).toEqual(feedUriBadPagination)
204
- expect(paginatedAll[2].uri).toEqual(feedUriEven)
205
- expect(paginatedAll[3].uri).toEqual(feedUriAll)
223
+ expect(paginatedAll[1].uri).toEqual(feedUriNeedsAuth)
224
+ expect(paginatedAll[2].uri).toEqual(feedUriBadPagination)
225
+ expect(paginatedAll[3].uri).toEqual(feedUriEven)
226
+ expect(paginatedAll[4].uri).toEqual(feedUriAll)
206
227
  expect(paginatedAll.map((fg) => fg.uri)).not.toContain(feedUriPrime) // taken-down
207
228
  expect(forSnapshot(paginatedAll)).toMatchSnapshot()
208
229
  })
@@ -348,7 +369,9 @@ describe('feed generation', () => {
348
369
  {},
349
370
  { headers: await network.serviceHeaders(sc.dids.bob) },
350
371
  )
351
- expect(resEven.data.feeds.map((f) => f.likeCount)).toEqual([2, 0, 0, 0])
372
+ expect(resEven.data.feeds.map((f) => f.likeCount)).toEqual([
373
+ 2, 0, 0, 0, 0,
374
+ ])
352
375
  expect(resEven.data.feeds.map((f) => f.uri)).not.toContain(feedUriPrime) // taken-down
353
376
  })
354
377
 
@@ -389,6 +412,16 @@ describe('feed generation', () => {
389
412
  expect(forSnapshot(feed.data.feed)).toMatchSnapshot()
390
413
  })
391
414
 
415
+ it('resolves basic feed contents without auth.', async () => {
416
+ const feed = await agent.api.app.bsky.feed.getFeed({ feed: feedUriEven })
417
+ expect(feed.data.feed.map((item) => item.post.uri)).toEqual([
418
+ sc.posts[sc.dids.alice][0].ref.uriStr,
419
+ sc.posts[sc.dids.carol][0].ref.uriStr,
420
+ sc.replies[sc.dids.carol][0].ref.uriStr,
421
+ ])
422
+ expect(forSnapshot(feed.data.feed)).toMatchSnapshot()
423
+ })
424
+
392
425
  it('paginates, handling replies and reposts.', async () => {
393
426
  const results = (results) => results.flatMap((res) => res.feed)
394
427
  const paginator = async (cursor?: string) => {
@@ -461,6 +494,16 @@ describe('feed generation', () => {
461
494
  expect(feed.data['$auth']?.['iss']).toEqual(alice)
462
495
  })
463
496
 
497
+ it('passes through auth error from feed.', async () => {
498
+ const tryGetFeed = agent.api.app.bsky.feed.getFeed({
499
+ feed: feedUriNeedsAuth,
500
+ })
501
+ const err = await tryGetFeed.catch((err) => err)
502
+ assert(err instanceof XRPCError)
503
+ expect(err.status).toBe(401)
504
+ expect(err.message).toBe('This feed requires auth')
505
+ })
506
+
464
507
  it('provides timing info in server-timing header.', async () => {
465
508
  const result = await agent.api.app.bsky.feed.getFeed(
466
509
  { feed: feedUriEven },
@@ -482,8 +525,13 @@ describe('feed generation', () => {
482
525
  })
483
526
 
484
527
  const feedGenHandler =
485
- (feedName: 'even' | 'all' | 'prime' | 'bad-pagination'): SkeletonHandler =>
528
+ (
529
+ feedName: 'even' | 'all' | 'prime' | 'bad-pagination' | 'needs-auth',
530
+ ): SkeletonHandler =>
486
531
  async ({ req, params }) => {
532
+ if (feedName === 'needs-auth' && !req.headers.authorization) {
533
+ throw new AuthRequiredError('This feed requires auth')
534
+ }
487
535
  const { limit, cursor } = params
488
536
  const candidates: SkeletonFeedPost[] = [
489
537
  { post: sc.posts[sc.dids.alice][0].ref.uriStr },
@@ -126,9 +126,6 @@ Object {
126
126
  "uri": "record(0)",
127
127
  "viewer": Object {},
128
128
  },
129
- "viewer": Object {
130
- "canReply": true,
131
- },
132
129
  },
133
130
  }
134
131
  `;
@@ -204,9 +201,6 @@ Object {
204
201
  "viewer": Object {},
205
202
  },
206
203
  "replies": Array [],
207
- "viewer": Object {
208
- "canReply": true,
209
- },
210
204
  },
211
205
  }
212
206
  `;
@@ -288,9 +282,6 @@ Object {
288
282
  "uri": "record(7)",
289
283
  },
290
284
  ],
291
- "viewer": Object {
292
- "canReply": true,
293
- },
294
285
  },
295
286
  }
296
287
  `;
@@ -498,6 +489,7 @@ Object {
498
489
  "muted": false,
499
490
  },
500
491
  },
492
+ "uri": "record(4)",
501
493
  },
502
494
  Object {
503
495
  "subject": Object {
@@ -522,6 +514,7 @@ Object {
522
514
  "muted": false,
523
515
  },
524
516
  },
517
+ "uri": "record(5)",
525
518
  },
526
519
  Object {
527
520
  "subject": Object {
@@ -550,6 +543,7 @@ Object {
550
543
  "muted": false,
551
544
  },
552
545
  },
546
+ "uri": "record(6)",
553
547
  },
554
548
  ],
555
549
  "list": Object {
@@ -126,9 +126,6 @@ Object {
126
126
  "uri": "record(0)",
127
127
  "viewer": Object {},
128
128
  },
129
- "viewer": Object {
130
- "canReply": true,
131
- },
132
129
  },
133
130
  }
134
131
  `;
@@ -204,9 +201,6 @@ Object {
204
201
  "viewer": Object {},
205
202
  },
206
203
  "replies": Array [],
207
- "viewer": Object {
208
- "canReply": true,
209
- },
210
204
  },
211
205
  }
212
206
  `;
@@ -359,9 +353,6 @@ Object {
359
353
  },
360
354
  },
361
355
  ],
362
- "viewer": Object {
363
- "canReply": true,
364
- },
365
356
  },
366
357
  }
367
358
  `;
@@ -292,9 +292,6 @@ Object {
292
292
  },
293
293
  },
294
294
  ],
295
- "viewer": Object {
296
- "canReply": true,
297
- },
298
295
  }
299
296
  `;
300
297
 
@@ -498,6 +495,7 @@ Object {
498
495
  "muted": false,
499
496
  },
500
497
  },
498
+ "uri": "record(3)",
501
499
  },
502
500
  Object {
503
501
  "subject": Object {
@@ -506,7 +504,7 @@ Object {
506
504
  "labels": Array [],
507
505
  "viewer": Object {
508
506
  "blockedBy": false,
509
- "followedBy": "record(3)",
507
+ "followedBy": "record(5)",
510
508
  "muted": true,
511
509
  "mutedByList": Object {
512
510
  "avatar": "https://bsky.public.url/img/avatar/plain/user(0)/cids(1)@jpeg",
@@ -521,6 +519,7 @@ Object {
521
519
  },
522
520
  },
523
521
  },
522
+ "uri": "record(4)",
524
523
  },
525
524
  Object {
526
525
  "subject": Object {
@@ -533,7 +532,7 @@ Object {
533
532
  "labels": Array [],
534
533
  "viewer": Object {
535
534
  "blockedBy": false,
536
- "following": "record(4)",
535
+ "following": "record(7)",
537
536
  "muted": true,
538
537
  "mutedByList": Object {
539
538
  "avatar": "https://bsky.public.url/img/avatar/plain/user(0)/cids(1)@jpeg",
@@ -548,6 +547,7 @@ Object {
548
547
  },
549
548
  },
550
549
  },
550
+ "uri": "record(6)",
551
551
  },
552
552
  ],
553
553
  "list": Object {
@@ -269,8 +269,5 @@ Object {
269
269
  },
270
270
  },
271
271
  ],
272
- "viewer": Object {
273
- "canReply": true,
274
- },
275
272
  }
276
273
  `;
@@ -195,9 +195,6 @@ Object {
195
195
  },
196
196
  },
197
197
  "replies": Array [],
198
- "viewer": Object {
199
- "canReply": true,
200
- },
201
198
  }
202
199
  `;
203
200
 
@@ -437,9 +434,6 @@ Object {
437
434
  ],
438
435
  },
439
436
  ],
440
- "viewer": Object {
441
- "canReply": true,
442
- },
443
437
  }
444
438
  `;
445
439
 
@@ -615,9 +609,6 @@ Object {
615
609
  },
616
610
  },
617
611
  ],
618
- "viewer": Object {
619
- "canReply": true,
620
- },
621
612
  }
622
613
  `;
623
614
 
@@ -771,9 +762,6 @@ Object {
771
762
  ],
772
763
  },
773
764
  ],
774
- "viewer": Object {
775
- "canReply": true,
776
- },
777
765
  }
778
766
  `;
779
767
 
@@ -826,9 +814,6 @@ Object {
826
814
  "viewer": Object {},
827
815
  },
828
816
  "replies": Array [],
829
- "viewer": Object {
830
- "canReply": true,
831
- },
832
817
  }
833
818
  `;
834
819
 
@@ -896,9 +881,6 @@ Object {
896
881
  "viewer": Object {},
897
882
  },
898
883
  "replies": Array [],
899
- "viewer": Object {
900
- "canReply": true,
901
- },
902
884
  }
903
885
  `;
904
886
 
@@ -968,9 +950,6 @@ Object {
968
950
  },
969
951
  },
970
952
  "replies": Array [],
971
- "viewer": Object {
972
- "canReply": true,
973
- },
974
953
  }
975
954
  `;
976
955
 
@@ -1040,9 +1019,6 @@ Object {
1040
1019
  },
1041
1020
  },
1042
1021
  "replies": Array [],
1043
- "viewer": Object {
1044
- "canReply": true,
1045
- },
1046
1022
  }
1047
1023
  `;
1048
1024
 
@@ -1243,9 +1219,6 @@ Object {
1243
1219
  ],
1244
1220
  },
1245
1221
  ],
1246
- "viewer": Object {
1247
- "canReply": true,
1248
- },
1249
1222
  }
1250
1223
  `;
1251
1224
 
@@ -1384,8 +1357,5 @@ Object {
1384
1357
  "replies": Array [],
1385
1358
  },
1386
1359
  ],
1387
- "viewer": Object {
1388
- "canReply": true,
1389
- },
1390
1360
  }
1391
1361
  `;
@@ -1,7 +1,6 @@
1
1
  import AtpAgent from '@atproto/api'
2
2
  import { wait } from '@atproto/common'
3
3
  import { TestNetwork, SeedClient } from '@atproto/dev-env'
4
- import { TAKEDOWN } from '@atproto/api/src/client/types/com/atproto/admin/defs'
5
4
  import { forSnapshot, paginateAll, stripViewer } from '../_util'
6
5
  import usersBulkSeed from '../seeds/users-bulk'
7
6
 
@@ -240,9 +239,9 @@ describe.skip('pds actor search views', () => {
240
239
  })
241
240
 
242
241
  it('search blocks by actor takedown', async () => {
243
- await agent.api.com.atproto.admin.takeModerationAction(
242
+ await agent.api.com.atproto.admin.emitModerationEvent(
244
243
  {
245
- action: TAKEDOWN,
244
+ event: { $type: 'com.atproto.admin.defs#modEventTakedown' },
246
245
  subject: {
247
246
  $type: 'com.atproto.admin.defs#repoRef',
248
247
  did: sc.dids['cara-wiegand69.test'],
@@ -2,7 +2,6 @@ import AtpAgent from '@atproto/api'
2
2
  import { TestNetwork, SeedClient } from '@atproto/dev-env'
3
3
  import { forSnapshot, paginateAll, stripViewerFromPost } from '../_util'
4
4
  import basicSeed from '../seeds/basic'
5
- import { TAKEDOWN } from '@atproto/api/src/client/types/com/atproto/admin/defs'
6
5
  import { isRecord } from '../../src/lexicon/types/app/bsky/feed/post'
7
6
  import { isView as isEmbedRecordWithMedia } from '../../src/lexicon/types/app/bsky/embed/recordWithMedia'
8
7
  import { isView as isImageEmbed } from '../../src/lexicon/types/app/bsky/embed/images'
@@ -146,22 +145,21 @@ describe('pds author feed views', () => {
146
145
 
147
146
  expect(preBlock.feed.length).toBeGreaterThan(0)
148
147
 
149
- const { data: action } =
150
- await agent.api.com.atproto.admin.takeModerationAction(
151
- {
152
- action: TAKEDOWN,
153
- subject: {
154
- $type: 'com.atproto.admin.defs#repoRef',
155
- did: alice,
156
- },
157
- createdBy: 'did:example:admin',
158
- reason: 'Y',
159
- },
160
- {
161
- encoding: 'application/json',
162
- headers: network.pds.adminAuthHeaders(),
148
+ await agent.api.com.atproto.admin.emitModerationEvent(
149
+ {
150
+ event: { $type: 'com.atproto.admin.defs#modEventTakedown' },
151
+ subject: {
152
+ $type: 'com.atproto.admin.defs#repoRef',
153
+ did: alice,
163
154
  },
164
- )
155
+ createdBy: 'did:example:admin',
156
+ reason: 'Y',
157
+ },
158
+ {
159
+ encoding: 'application/json',
160
+ headers: network.pds.adminAuthHeaders(),
161
+ },
162
+ )
165
163
 
166
164
  const attempt = agent.api.app.bsky.feed.getAuthorFeed(
167
165
  { actor: alice },
@@ -170,9 +168,13 @@ describe('pds author feed views', () => {
170
168
  await expect(attempt).rejects.toThrow('Profile not found')
171
169
 
172
170
  // Cleanup
173
- await agent.api.com.atproto.admin.reverseModerationAction(
171
+ await agent.api.com.atproto.admin.emitModerationEvent(
174
172
  {
175
- id: action.id,
173
+ event: { $type: 'com.atproto.admin.defs#modEventReverseTakedown' },
174
+ subject: {
175
+ $type: 'com.atproto.admin.defs#repoRef',
176
+ did: alice,
177
+ },
176
178
  createdBy: 'did:example:admin',
177
179
  reason: 'Y',
178
180
  },
@@ -193,23 +195,22 @@ describe('pds author feed views', () => {
193
195
 
194
196
  const post = preBlock.feed[0].post
195
197
 
196
- const { data: action } =
197
- await agent.api.com.atproto.admin.takeModerationAction(
198
- {
199
- action: TAKEDOWN,
200
- subject: {
201
- $type: 'com.atproto.repo.strongRef',
202
- uri: post.uri,
203
- cid: post.cid,
204
- },
205
- createdBy: 'did:example:admin',
206
- reason: 'Y',
207
- },
208
- {
209
- encoding: 'application/json',
210
- headers: network.pds.adminAuthHeaders(),
198
+ await agent.api.com.atproto.admin.emitModerationEvent(
199
+ {
200
+ event: { $type: 'com.atproto.admin.defs#modEventTakedown' },
201
+ subject: {
202
+ $type: 'com.atproto.repo.strongRef',
203
+ uri: post.uri,
204
+ cid: post.cid,
211
205
  },
212
- )
206
+ createdBy: 'did:example:admin',
207
+ reason: 'Y',
208
+ },
209
+ {
210
+ encoding: 'application/json',
211
+ headers: network.pds.adminAuthHeaders(),
212
+ },
213
+ )
213
214
 
214
215
  const { data: postBlock } = await agent.api.app.bsky.feed.getAuthorFeed(
215
216
  { actor: alice },
@@ -220,9 +221,14 @@ describe('pds author feed views', () => {
220
221
  expect(postBlock.feed.map((item) => item.post.uri)).not.toContain(post.uri)
221
222
 
222
223
  // Cleanup
223
- await agent.api.com.atproto.admin.reverseModerationAction(
224
+ await agent.api.com.atproto.admin.emitModerationEvent(
224
225
  {
225
- id: action.id,
226
+ event: { $type: 'com.atproto.admin.defs#modEventReverseTakedown' },
227
+ subject: {
228
+ $type: 'com.atproto.repo.strongRef',
229
+ uri: post.uri,
230
+ cid: post.cid,
231
+ },
226
232
  createdBy: 'did:example:admin',
227
233
  reason: 'Y',
228
234
  },