@atproto/ozone 0.0.16 → 0.0.17-next.1

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 (157) hide show
  1. package/dist/api/util.d.ts +10 -0
  2. package/dist/auth-verifier.d.ts +8 -12
  3. package/dist/communication-service/template.d.ts +2 -2
  4. package/dist/config/config.d.ts +6 -0
  5. package/dist/config/env.d.ts +3 -2
  6. package/dist/config/secrets.d.ts +0 -2
  7. package/dist/context.d.ts +6 -0
  8. package/dist/daemon/blob-diverter.d.ts +26 -0
  9. package/dist/daemon/event-pusher.d.ts +6 -0
  10. package/dist/daemon/index.d.ts +1 -0
  11. package/dist/db/index.js +21 -1
  12. package/dist/db/index.js.map +3 -3
  13. package/dist/db/migrations/20240228T003647759Z-add-label-sigs.d.ts +3 -0
  14. package/dist/db/migrations/index.d.ts +1 -0
  15. package/dist/db/schema/index.d.ts +2 -1
  16. package/dist/db/schema/label.d.ts +4 -0
  17. package/dist/db/schema/moderation_event.d.ts +1 -1
  18. package/dist/db/schema/moderation_subject_status.d.ts +2 -2
  19. package/dist/db/schema/signing_key.d.ts +9 -0
  20. package/dist/index.js +10400 -10313
  21. package/dist/index.js.map +3 -3
  22. package/dist/lexicon/index.d.ts +55 -27
  23. package/dist/lexicon/lexicons.d.ts +5046 -4757
  24. package/dist/lexicon/types/app/bsky/actor/defs.d.ts +23 -1
  25. package/dist/lexicon/types/app/bsky/embed/record.d.ts +2 -1
  26. package/dist/lexicon/types/app/bsky/feed/defs.d.ts +1 -0
  27. package/dist/lexicon/types/app/bsky/graph/defs.d.ts +3 -0
  28. package/dist/lexicon/types/app/bsky/labeler/defs.d.ts +41 -0
  29. package/dist/lexicon/types/app/bsky/labeler/getServices.d.ts +36 -0
  30. package/dist/lexicon/types/app/bsky/labeler/service.d.ts +14 -0
  31. package/dist/lexicon/types/com/atproto/admin/defs.d.ts +0 -304
  32. package/dist/lexicon/types/com/atproto/label/defs.d.ts +23 -0
  33. package/dist/lexicon/types/{com/atproto/admin/createCommunicationTemplate.d.ts → tools/ozone/communication/createTemplate.d.ts} +2 -2
  34. package/dist/lexicon/types/tools/ozone/communication/defs.d.ts +14 -0
  35. package/dist/lexicon/types/{com/atproto/admin/listCommunicationTemplates.d.ts → tools/ozone/communication/listTemplates.d.ts} +2 -2
  36. package/dist/lexicon/types/{com/atproto/admin/updateCommunicationTemplate.d.ts → tools/ozone/communication/updateTemplate.d.ts} +2 -2
  37. package/dist/lexicon/types/tools/ozone/moderation/defs.d.ts +269 -0
  38. package/dist/lexicon/types/{com/atproto/admin/emitModerationEvent.d.ts → tools/ozone/moderation/emitEvent.d.ts} +5 -4
  39. package/dist/lexicon/types/{com/atproto/admin/getModerationEvent.d.ts → tools/ozone/moderation/getEvent.d.ts} +2 -2
  40. package/dist/lexicon/types/{com/atproto/admin → tools/ozone/moderation}/getRecord.d.ts +2 -2
  41. package/dist/lexicon/types/{com/atproto/admin → tools/ozone/moderation}/getRepo.d.ts +2 -2
  42. package/dist/lexicon/types/{com/atproto/admin/queryModerationEvents.d.ts → tools/ozone/moderation/queryEvents.d.ts} +2 -2
  43. package/dist/lexicon/types/{com/atproto/admin/queryModerationStatuses.d.ts → tools/ozone/moderation/queryStatuses.d.ts} +2 -2
  44. package/dist/lexicon/types/{com/atproto/admin → tools/ozone/moderation}/searchRepos.d.ts +2 -2
  45. package/dist/mod-service/index.d.ts +16 -15
  46. package/dist/mod-service/subject.d.ts +1 -1
  47. package/dist/mod-service/types.d.ts +2 -2
  48. package/dist/mod-service/util.d.ts +6 -0
  49. package/dist/mod-service/views.d.ts +9 -3
  50. package/dist/sequencer/sequencer.d.ts +6 -4
  51. package/dist/util.d.ts +2 -0
  52. package/package.json +9 -8
  53. package/src/api/{admin/createCommunicationTemplate.ts → communication/createTemplate.ts} +2 -2
  54. package/src/api/{admin/deleteCommunicationTemplate.ts → communication/deleteTemplate.ts} +2 -2
  55. package/src/api/{admin/listCommunicationTemplates.ts → communication/listTemplates.ts} +2 -2
  56. package/src/api/{admin/updateCommunicationTemplate.ts → communication/updateTemplate.ts} +2 -2
  57. package/src/api/index.ts +21 -21
  58. package/src/api/{temp → label}/fetchLabels.ts +5 -3
  59. package/src/api/label/queryLabels.ts +4 -2
  60. package/src/api/moderation/emitEvent.ts +218 -0
  61. package/src/api/{admin/getModerationEvent.ts → moderation/getEvent.ts} +2 -2
  62. package/src/api/{admin → moderation}/getRecord.ts +3 -3
  63. package/src/api/{admin → moderation}/getRepo.ts +3 -3
  64. package/src/api/{admin/queryModerationEvents.ts → moderation/queryEvents.ts} +3 -3
  65. package/src/api/{admin/queryModerationStatuses.ts → moderation/queryStatuses.ts} +3 -3
  66. package/src/api/{admin → moderation}/searchRepos.ts +2 -2
  67. package/src/api/proxied.ts +8 -8
  68. package/src/api/{moderation → report}/createReport.ts +2 -3
  69. package/src/api/util.ts +119 -0
  70. package/src/auth-verifier.ts +20 -30
  71. package/src/communication-service/template.ts +2 -2
  72. package/src/config/config.ts +24 -7
  73. package/src/config/env.ts +6 -4
  74. package/src/config/secrets.ts +0 -6
  75. package/src/context.ts +36 -12
  76. package/src/daemon/blob-diverter.ts +150 -0
  77. package/src/daemon/context.ts +11 -7
  78. package/src/daemon/event-pusher.ts +58 -15
  79. package/src/daemon/index.ts +1 -0
  80. package/src/db/migrations/20240228T003647759Z-add-label-sigs.ts +25 -0
  81. package/src/db/migrations/index.ts +1 -0
  82. package/src/db/schema/index.ts +2 -0
  83. package/src/db/schema/label.ts +3 -0
  84. package/src/db/schema/moderation_event.ts +11 -11
  85. package/src/db/schema/moderation_subject_status.ts +7 -2
  86. package/src/db/schema/signing_key.ts +10 -0
  87. package/src/lexicon/index.ts +200 -137
  88. package/src/lexicon/lexicons.ts +6310 -6012
  89. package/src/lexicon/types/app/bsky/actor/defs.ts +57 -1
  90. package/src/lexicon/types/app/bsky/embed/record.ts +2 -0
  91. package/src/lexicon/types/app/bsky/feed/defs.ts +1 -0
  92. package/src/lexicon/types/app/bsky/graph/defs.ts +3 -0
  93. package/src/lexicon/types/app/bsky/labeler/defs.ts +93 -0
  94. package/src/lexicon/types/app/bsky/labeler/getServices.ts +51 -0
  95. package/src/lexicon/types/app/bsky/labeler/service.ts +31 -0
  96. package/src/lexicon/types/com/atproto/admin/defs.ts +0 -694
  97. package/src/lexicon/types/com/atproto/label/defs.ts +78 -0
  98. package/src/lexicon/types/{com/atproto/admin/createCommunicationTemplate.ts → tools/ozone/communication/createTemplate.ts} +2 -2
  99. package/src/lexicon/types/tools/ozone/communication/defs.ts +35 -0
  100. package/src/lexicon/types/{com/atproto/admin/listCommunicationTemplates.ts → tools/ozone/communication/listTemplates.ts} +2 -2
  101. package/src/lexicon/types/{com/atproto/admin/updateCommunicationTemplate.ts → tools/ozone/communication/updateTemplate.ts} +2 -2
  102. package/src/lexicon/types/tools/ozone/moderation/defs.ts +641 -0
  103. package/src/lexicon/types/{com/atproto/admin/emitModerationEvent.ts → tools/ozone/moderation/emitEvent.ts} +15 -14
  104. package/src/lexicon/types/{com/atproto/admin/getModerationEvent.ts → tools/ozone/moderation/getEvent.ts} +2 -2
  105. package/src/lexicon/types/{com/atproto/admin → tools/ozone/moderation}/getRecord.ts +2 -2
  106. package/src/lexicon/types/{com/atproto/admin → tools/ozone/moderation}/getRepo.ts +2 -2
  107. package/src/lexicon/types/{com/atproto/admin/queryModerationEvents.ts → tools/ozone/moderation/queryEvents.ts} +3 -3
  108. package/src/lexicon/types/{com/atproto/admin/queryModerationStatuses.ts → tools/ozone/moderation/queryStatuses.ts} +2 -2
  109. package/src/lexicon/types/{com/atproto/admin → tools/ozone/moderation}/searchRepos.ts +2 -2
  110. package/src/mod-service/index.ts +46 -50
  111. package/src/mod-service/lang.ts +1 -1
  112. package/src/mod-service/status.ts +60 -41
  113. package/src/mod-service/subject.ts +1 -1
  114. package/src/mod-service/types.ts +10 -10
  115. package/src/mod-service/util.ts +49 -5
  116. package/src/mod-service/views.ts +45 -18
  117. package/src/sequencer/sequencer.ts +12 -11
  118. package/src/util.ts +21 -0
  119. package/tests/__snapshots__/blob-divert.test.ts.snap +22 -0
  120. package/tests/__snapshots__/get-record.test.ts.snap +14 -6
  121. package/tests/__snapshots__/get-repo.test.ts.snap +7 -3
  122. package/tests/__snapshots__/moderation-events.test.ts.snap +8 -8
  123. package/tests/__snapshots__/moderation-statuses.test.ts.snap +6 -6
  124. package/tests/_util.ts +5 -0
  125. package/tests/blob-divert.test.ts +87 -0
  126. package/tests/communication-templates.test.ts +33 -37
  127. package/tests/db.test.ts +6 -6
  128. package/tests/get-record.test.ts +22 -12
  129. package/tests/get-repo.test.ts +33 -21
  130. package/tests/moderation-appeals.test.ts +39 -67
  131. package/tests/moderation-events.test.ts +99 -142
  132. package/tests/moderation-status-tags.test.ts +20 -37
  133. package/tests/moderation-statuses.test.ts +132 -65
  134. package/tests/moderation.test.ts +147 -301
  135. package/tests/query-labels.test.ts +86 -10
  136. package/tests/repo-search.test.ts +18 -11
  137. package/tests/sequencer.test.ts +6 -3
  138. package/dist/api/admin/util.d.ts +0 -5
  139. package/dist/api/moderation/util.d.ts +0 -4
  140. package/src/api/admin/emitModerationEvent.ts +0 -170
  141. package/src/api/admin/util.ts +0 -54
  142. package/src/api/moderation/util.ts +0 -67
  143. /package/dist/api/{admin/createCommunicationTemplate.d.ts → communication/createTemplate.d.ts} +0 -0
  144. /package/dist/api/{admin/deleteCommunicationTemplate.d.ts → communication/deleteTemplate.d.ts} +0 -0
  145. /package/dist/api/{admin/emitModerationEvent.d.ts → communication/listTemplates.d.ts} +0 -0
  146. /package/dist/api/{admin/getModerationEvent.d.ts → communication/updateTemplate.d.ts} +0 -0
  147. /package/dist/api/{temp → label}/fetchLabels.d.ts +0 -0
  148. /package/dist/api/{admin/getRecord.d.ts → moderation/emitEvent.d.ts} +0 -0
  149. /package/dist/api/{admin/getRepo.d.ts → moderation/getEvent.d.ts} +0 -0
  150. /package/dist/api/{admin/listCommunicationTemplates.d.ts → moderation/getRecord.d.ts} +0 -0
  151. /package/dist/api/{admin/queryModerationEvents.d.ts → moderation/getRepo.d.ts} +0 -0
  152. /package/dist/api/{admin/queryModerationStatuses.d.ts → moderation/queryEvents.d.ts} +0 -0
  153. /package/dist/api/{admin/searchRepos.d.ts → moderation/queryStatuses.d.ts} +0 -0
  154. /package/dist/api/{admin/updateCommunicationTemplate.d.ts → moderation/searchRepos.d.ts} +0 -0
  155. /package/dist/api/{moderation → report}/createReport.d.ts +0 -0
  156. /package/dist/lexicon/types/{com/atproto/admin/deleteCommunicationTemplate.d.ts → tools/ozone/communication/deleteTemplate.d.ts} +0 -0
  157. /package/src/lexicon/types/{com/atproto/admin/deleteCommunicationTemplate.ts → tools/ozone/communication/deleteTemplate.ts} +0 -0
@@ -4,12 +4,9 @@ import {
4
4
  RecordRef,
5
5
  SeedClient,
6
6
  basicSeed,
7
+ ModeratorClient,
7
8
  } from '@atproto/dev-env'
8
- import AtpAgent, {
9
- ComAtprotoAdminEmitModerationEvent,
10
- ComAtprotoAdminQueryModerationStatuses,
11
- ComAtprotoModerationCreateReport,
12
- } from '@atproto/api'
9
+ import AtpAgent, { ToolsOzoneModerationEmitEvent } from '@atproto/api'
13
10
  import { AtUri } from '@atproto/syntax'
14
11
  import { forSnapshot } from './_util'
15
12
  import {
@@ -19,10 +16,9 @@ import {
19
16
  } from '../src/lexicon/types/com/atproto/moderation/defs'
20
17
  import {
21
18
  ModEventLabel,
22
- ModEventTakedown,
23
19
  REVIEWCLOSED,
24
20
  REVIEWESCALATED,
25
- } from '../src/lexicon/types/com/atproto/admin/defs'
21
+ } from '../src/lexicon/types/tools/ozone/moderation/defs'
26
22
  import { EventReverser } from '../src'
27
23
  import { TestOzone } from '@atproto/dev-env/src/ozone'
28
24
  import { ImageInvalidator } from '../src/image-invalidator'
@@ -31,16 +27,6 @@ import {
31
27
  UNSPECCED_TAKEDOWN_LABEL,
32
28
  } from '../src/mod-service/types'
33
29
 
34
- type BaseCreateReportParams =
35
- | { account: string }
36
- | { content: { uri: string; cid: string } }
37
- type CreateReportParams = BaseCreateReportParams & {
38
- author: string
39
- } & Omit<ComAtprotoModerationCreateReport.InputSchema, 'subject'>
40
-
41
- type TakedownParams = BaseCreateReportParams &
42
- Omit<ComAtprotoAdminEmitModerationEvent.InputSchema, 'subject'>
43
-
44
30
  describe('moderation', () => {
45
31
  let network: TestNetwork
46
32
  let ozone: TestOzone
@@ -49,102 +35,18 @@ describe('moderation', () => {
49
35
  let bskyAgent: AtpAgent
50
36
  let pdsAgent: AtpAgent
51
37
  let sc: SeedClient
38
+ let modClient: ModeratorClient
52
39
 
53
- const createReport = async (params: CreateReportParams) => {
54
- const { author, ...rest } = params
55
- return agent.api.com.atproto.moderation.createReport(
56
- {
57
- // Set default type to spam
58
- reasonType: REASONSPAM,
59
- ...rest,
60
- subject:
61
- 'account' in params
62
- ? {
63
- $type: 'com.atproto.admin.defs#repoRef',
64
- did: params.account,
65
- }
66
- : {
67
- $type: 'com.atproto.repo.strongRef',
68
- uri: params.content.uri,
69
- cid: params.content.cid,
70
- },
71
- },
72
- {
73
- headers: await network.serviceHeaders(
74
- author,
75
- network.ozone.ctx.cfg.service.did,
76
- ),
77
- encoding: 'application/json',
78
- },
79
- )
80
- }
81
-
82
- const performTakedown = async ({
83
- durationInHours,
84
- ...rest
85
- }: TakedownParams & Pick<ModEventTakedown, 'durationInHours'>) =>
86
- agent.api.com.atproto.admin.emitModerationEvent(
87
- {
88
- event: {
89
- $type: 'com.atproto.admin.defs#modEventTakedown',
90
- durationInHours,
91
- },
92
- subject:
93
- 'account' in rest
94
- ? {
95
- $type: 'com.atproto.admin.defs#repoRef',
96
- did: rest.account,
97
- }
98
- : {
99
- $type: 'com.atproto.repo.strongRef',
100
- uri: rest.content.uri,
101
- cid: rest.content.cid,
102
- },
103
- createdBy: 'did:example:admin',
104
- ...rest,
105
- },
106
- {
107
- encoding: 'application/json',
108
- headers: ozone.adminAuthHeaders(),
109
- },
110
- )
111
-
112
- const performReverseTakedown = async (params: TakedownParams) =>
113
- agent.api.com.atproto.admin.emitModerationEvent(
114
- {
115
- event: {
116
- $type: 'com.atproto.admin.defs#modEventReverseTakedown',
117
- },
118
- subject:
119
- 'account' in params
120
- ? {
121
- $type: 'com.atproto.admin.defs#repoRef',
122
- did: params.account,
123
- }
124
- : {
125
- $type: 'com.atproto.repo.strongRef',
126
- uri: params.content.uri,
127
- cid: params.content.cid,
128
- },
129
- createdBy: 'did:example:admin',
130
- ...params,
131
- },
132
- {
133
- encoding: 'application/json',
134
- headers: ozone.adminAuthHeaders(),
135
- },
136
- )
137
-
138
- const getStatuses = async (
139
- params: ComAtprotoAdminQueryModerationStatuses.QueryParams,
140
- ) => {
141
- const { data } = await agent.api.com.atproto.admin.queryModerationStatuses(
142
- params,
143
- { headers: ozone.adminAuthHeaders() },
144
- )
40
+ const repoSubject = (did: string) => ({
41
+ $type: 'com.atproto.admin.defs#repoRef',
42
+ did,
43
+ })
145
44
 
146
- return data
147
- }
45
+ const recordSubject = (ref: RecordRef) => ({
46
+ $type: 'com.atproto.repo.strongRef',
47
+ uri: ref.uriStr,
48
+ cid: ref.cidStr,
49
+ })
148
50
 
149
51
  const getLabel = async (uri: string, val: string, neg = false) => {
150
52
  return ozone.ctx.db.db
@@ -170,6 +72,7 @@ describe('moderation', () => {
170
72
  bskyAgent = network.bsky.getClient()
171
73
  pdsAgent = network.pds.getClient()
172
74
  sc = network.getSeedClient()
75
+ modClient = network.ozone.getModClient()
173
76
  await basicSeed(sc)
174
77
  await network.processAll()
175
78
  })
@@ -180,25 +83,25 @@ describe('moderation', () => {
180
83
 
181
84
  describe('reporting', () => {
182
85
  it('creates reports of a repo.', async () => {
183
- const { data: reportA } = await createReport({
86
+ const reportA = await sc.createReport({
184
87
  reasonType: REASONSPAM,
185
- account: sc.dids.bob,
186
- author: sc.dids.alice,
88
+ subject: repoSubject(sc.dids.bob),
89
+ reportedBy: sc.dids.alice,
187
90
  })
188
- const { data: reportB } = await createReport({
91
+ const reportB = await sc.createReport({
189
92
  reasonType: REASONOTHER,
190
93
  reason: 'impersonation',
191
- account: sc.dids.bob,
192
- author: sc.dids.carol,
94
+ subject: repoSubject(sc.dids.bob),
95
+ reportedBy: sc.dids.carol,
193
96
  })
194
97
  expect(forSnapshot([reportA, reportB])).toMatchSnapshot()
195
98
  })
196
99
 
197
100
  it("allows reporting a repo that doesn't exist.", async () => {
198
- const promise = createReport({
101
+ const promise = sc.createReport({
199
102
  reasonType: REASONSPAM,
200
- account: 'did:plc:unknown',
201
- author: sc.dids.alice,
103
+ subject: repoSubject('did:plc:unknown'),
104
+ reportedBy: sc.dids.alice,
202
105
  })
203
106
  await expect(promise).resolves.toBeDefined()
204
107
  })
@@ -206,24 +109,16 @@ describe('moderation', () => {
206
109
  it('creates reports of a record.', async () => {
207
110
  const postA = sc.posts[sc.dids.bob][0].ref
208
111
  const postB = sc.posts[sc.dids.bob][1].ref
209
- const { data: reportA } = await createReport({
210
- author: sc.dids.alice,
112
+ const reportA = await sc.createReport({
113
+ reportedBy: sc.dids.alice,
211
114
  reasonType: REASONSPAM,
212
- content: {
213
- $type: 'com.atproto.repo.strongRef',
214
- uri: postA.uriStr,
215
- cid: postA.cidStr,
216
- },
115
+ subject: recordSubject(postA),
217
116
  })
218
- const { data: reportB } = await createReport({
117
+ const reportB = await sc.createReport({
219
118
  reasonType: REASONOTHER,
220
119
  reason: 'defamation',
221
- content: {
222
- $type: 'com.atproto.repo.strongRef',
223
- uri: postB.uriStr,
224
- cid: postB.cidStr,
225
- },
226
- author: sc.dids.carol,
120
+ subject: recordSubject(postB),
121
+ reportedBy: sc.dids.carol,
227
122
  })
228
123
  expect(forSnapshot([reportA, reportB])).toMatchSnapshot()
229
124
  })
@@ -234,26 +129,26 @@ describe('moderation', () => {
234
129
  const postUriBad = new AtUri(postA.uriStr)
235
130
  postUriBad.rkey = 'badrkey'
236
131
 
237
- const promiseA = createReport({
132
+ const promiseA = sc.createReport({
238
133
  reasonType: REASONSPAM,
239
- content: {
134
+ subject: {
240
135
  $type: 'com.atproto.repo.strongRef',
241
136
  uri: postUriBad.toString(),
242
137
  cid: postA.cidStr,
243
138
  },
244
- author: sc.dids.alice,
139
+ reportedBy: sc.dids.alice,
245
140
  })
246
141
  await expect(promiseA).resolves.toBeDefined()
247
142
 
248
- const promiseB = createReport({
143
+ const promiseB = sc.createReport({
249
144
  reasonType: REASONOTHER,
250
145
  reason: 'defamation',
251
- content: {
146
+ subject: {
252
147
  $type: 'com.atproto.repo.strongRef',
253
148
  uri: postB.uri.toString(),
254
149
  cid: postA.cidStr, // bad cid
255
150
  },
256
- author: sc.dids.carol,
151
+ reportedBy: sc.dids.carol,
257
152
  })
258
153
  await expect(promiseB).resolves.toBeDefined()
259
154
  })
@@ -264,27 +159,24 @@ describe('moderation', () => {
264
159
  const post = sc.posts[sc.dids.bob][1].ref
265
160
 
266
161
  await Promise.all([
267
- createReport({
162
+ sc.createReport({
268
163
  reasonType: REASONSPAM,
269
- account: sc.dids.bob,
270
- author: sc.dids.alice,
164
+ subject: repoSubject(sc.dids.bob),
165
+ reportedBy: sc.dids.alice,
271
166
  }),
272
- createReport({
167
+ sc.createReport({
273
168
  reasonType: REASONOTHER,
274
169
  reason: 'defamation',
275
- content: {
276
- uri: post.uri.toString(),
277
- cid: post.cid.toString(),
278
- },
279
- author: sc.dids.carol,
170
+ subject: recordSubject(post),
171
+ reportedBy: sc.dids.carol,
280
172
  }),
281
173
  ])
282
174
 
283
- await performTakedown({
284
- account: sc.dids.bob,
175
+ await modClient.performTakedown({
176
+ subject: repoSubject(sc.dids.bob),
285
177
  })
286
178
 
287
- const moderationStatusOnBobsAccount = await getStatuses({
179
+ const moderationStatusOnBobsAccount = await modClient.queryStatuses({
288
180
  subject: sc.dids.bob,
289
181
  })
290
182
 
@@ -299,8 +191,8 @@ describe('moderation', () => {
299
191
  })
300
192
 
301
193
  // Cleanup
302
- await performReverseTakedown({
303
- account: sc.dids.bob,
194
+ await modClient.performReverseTakedown({
195
+ subject: repoSubject(sc.dids.bob),
304
196
  })
305
197
  })
306
198
 
@@ -311,22 +203,19 @@ describe('moderation', () => {
311
203
  uri: alicesPostRef.uri.toString(),
312
204
  cid: alicesPostRef.cid.toString(),
313
205
  }
314
- await agent.api.com.atproto.admin.emitModerationEvent(
206
+ await modClient.emitEvent(
315
207
  {
316
208
  event: {
317
- $type: 'com.atproto.admin.defs#modEventEscalate',
209
+ $type: 'tools.ozone.moderation.defs#modEventEscalate',
318
210
  comment: 'Y',
319
211
  },
320
212
  subject: alicesPostSubject,
321
213
  createdBy: 'did:example:admin',
322
214
  },
323
- {
324
- encoding: 'application/json',
325
- headers: ozone.adminAuthHeaders('triage'),
326
- },
215
+ 'triage',
327
216
  )
328
217
 
329
- const alicesPostStatus = await getStatuses({
218
+ const alicesPostStatus = await modClient.queryStatuses({
330
219
  subject: alicesPostRef.uri.toString(),
331
220
  })
332
221
 
@@ -344,23 +233,20 @@ describe('moderation', () => {
344
233
  uri: alicesPostRef.uri.toString(),
345
234
  cid: alicesPostRef.cid.toString(),
346
235
  }
347
- await agent.api.com.atproto.admin.emitModerationEvent(
236
+ await modClient.emitEvent(
348
237
  {
349
238
  event: {
350
- $type: 'com.atproto.admin.defs#modEventComment',
239
+ $type: 'tools.ozone.moderation.defs#modEventComment',
351
240
  sticky: true,
352
241
  comment: 'This is a persistent note',
353
242
  },
354
243
  subject: alicesPostSubject,
355
244
  createdBy: 'did:example:admin',
356
245
  },
357
- {
358
- encoding: 'application/json',
359
- headers: ozone.adminAuthHeaders('triage'),
360
- },
246
+ 'triage',
361
247
  )
362
248
 
363
- const alicesPostStatus = await getStatuses({
249
+ const alicesPostStatus = await modClient.queryStatuses({
364
250
  subject: alicesPostRef.uri.toString(),
365
251
  })
366
252
 
@@ -372,8 +258,8 @@ describe('moderation', () => {
372
258
  it('reverses status when revert event is triggered.', async () => {
373
259
  const alicesPostRef = sc.posts[sc.dids.alice][0].ref
374
260
  const emitModEvent = async (
375
- event: ComAtprotoAdminEmitModerationEvent.InputSchema['event'],
376
- overwrites: Partial<ComAtprotoAdminEmitModerationEvent.InputSchema> = {},
261
+ event: ToolsOzoneModerationEmitEvent.InputSchema['event'],
262
+ overwrites: Partial<ToolsOzoneModerationEmitEvent.InputSchema> = {},
377
263
  ) => {
378
264
  const baseAction = {
379
265
  subject: {
@@ -383,31 +269,25 @@ describe('moderation', () => {
383
269
  },
384
270
  createdBy: 'did:example:admin',
385
271
  }
386
- return agent.api.com.atproto.admin.emitModerationEvent(
387
- {
388
- event,
389
- ...baseAction,
390
- ...overwrites,
391
- },
392
- {
393
- encoding: 'application/json',
394
- headers: ozone.adminAuthHeaders(),
395
- },
396
- )
272
+ return modClient.emitEvent({
273
+ event,
274
+ ...baseAction,
275
+ ...overwrites,
276
+ })
397
277
  }
398
278
  // Validate that subject status is marked as escalated
399
279
  await emitModEvent({
400
- $type: 'com.atproto.admin.defs#modEventReport',
280
+ $type: 'tools.ozone.moderation.defs#modEventReport',
401
281
  reportType: REASONSPAM,
402
282
  })
403
283
  await emitModEvent({
404
- $type: 'com.atproto.admin.defs#modEventReport',
284
+ $type: 'tools.ozone.moderation.defs#modEventReport',
405
285
  reportType: REASONMISLEADING,
406
286
  })
407
287
  await emitModEvent({
408
- $type: 'com.atproto.admin.defs#modEventEscalate',
288
+ $type: 'tools.ozone.moderation.defs#modEventEscalate',
409
289
  })
410
- const alicesPostStatusAfterEscalation = await getStatuses({
290
+ const alicesPostStatusAfterEscalation = await modClient.queryStatuses({
411
291
  subject: alicesPostRef.uriStr,
412
292
  })
413
293
  expect(
@@ -417,15 +297,15 @@ describe('moderation', () => {
417
297
  // Validate that subject status is marked as takendown
418
298
 
419
299
  await emitModEvent({
420
- $type: 'com.atproto.admin.defs#modEventLabel',
300
+ $type: 'tools.ozone.moderation.defs#modEventLabel',
421
301
  createLabelVals: ['nsfw'],
422
302
  negateLabelVals: [],
423
303
  })
424
304
  await emitModEvent({
425
- $type: 'com.atproto.admin.defs#modEventTakedown',
305
+ $type: 'tools.ozone.moderation.defs#modEventTakedown',
426
306
  })
427
307
 
428
- const alicesPostStatusAfterTakedown = await getStatuses({
308
+ const alicesPostStatusAfterTakedown = await modClient.queryStatuses({
429
309
  subject: alicesPostRef.uriStr,
430
310
  })
431
311
  expect(alicesPostStatusAfterTakedown.subjectStatuses[0]).toMatchObject({
@@ -434,9 +314,9 @@ describe('moderation', () => {
434
314
  })
435
315
 
436
316
  await emitModEvent({
437
- $type: 'com.atproto.admin.defs#modEventReverseTakedown',
317
+ $type: 'tools.ozone.moderation.defs#modEventReverseTakedown',
438
318
  })
439
- const alicesPostStatusAfterRevert = await getStatuses({
319
+ const alicesPostStatusAfterRevert = await modClient.queryStatuses({
440
320
  subject: alicesPostRef.uriStr,
441
321
  })
442
322
  // Validate that after reverting, the status of the subject is reverted to the last status changing event
@@ -598,10 +478,10 @@ describe('moderation', () => {
598
478
  })
599
479
 
600
480
  it('does not allow triage moderators to label.', async () => {
601
- const attemptLabel = agent.api.com.atproto.admin.emitModerationEvent(
481
+ const attemptLabel = modClient.emitEvent(
602
482
  {
603
483
  event: {
604
- $type: 'com.atproto.admin.defs#modEventLabel',
484
+ $type: 'tools.ozone.moderation.defs#modEventLabel',
605
485
  negateLabelVals: ['a'],
606
486
  createLabelVals: ['b', 'c'],
607
487
  },
@@ -612,10 +492,7 @@ describe('moderation', () => {
612
492
  did: sc.dids.bob,
613
493
  },
614
494
  },
615
- {
616
- encoding: 'application/json',
617
- headers: network.ozone.adminAuthHeaders('triage'),
618
- },
495
+ 'triage',
619
496
  )
620
497
  await expect(attemptLabel).rejects.toThrow(
621
498
  'Must be a full moderator to label content',
@@ -623,29 +500,29 @@ describe('moderation', () => {
623
500
  })
624
501
 
625
502
  it('does not allow take down event on takendown post or reverse takedown on available post.', async () => {
626
- await performTakedown({
627
- account: sc.dids.bob,
503
+ await modClient.performTakedown({
504
+ subject: repoSubject(sc.dids.bob),
628
505
  })
629
506
  await expect(
630
- performTakedown({
631
- account: sc.dids.bob,
507
+ modClient.performTakedown({
508
+ subject: repoSubject(sc.dids.bob),
632
509
  }),
633
510
  ).rejects.toThrow('Subject is already taken down')
634
511
 
635
512
  // Cleanup
636
- await performReverseTakedown({
637
- account: sc.dids.bob,
513
+ await modClient.performReverseTakedown({
514
+ subject: repoSubject(sc.dids.bob),
638
515
  })
639
516
  await expect(
640
- performReverseTakedown({
641
- account: sc.dids.bob,
517
+ modClient.performReverseTakedown({
518
+ subject: repoSubject(sc.dids.bob),
642
519
  }),
643
520
  ).rejects.toThrow('Subject is not taken down')
644
521
  })
645
522
 
646
523
  it('fans out repo takedowns', async () => {
647
- await performTakedown({
648
- account: sc.dids.bob,
524
+ await modClient.performTakedown({
525
+ subject: repoSubject(sc.dids.bob),
649
526
  })
650
527
  await ozone.processAll()
651
528
 
@@ -672,7 +549,9 @@ describe('moderation', () => {
672
549
  expect(takedownLabel1).toBeDefined()
673
550
 
674
551
  // cleanup
675
- await performReverseTakedown({ account: sc.dids.bob })
552
+ await modClient.performReverseTakedown({
553
+ subject: repoSubject(sc.dids.bob),
554
+ })
676
555
  await ozone.processAll()
677
556
 
678
557
  const pdsRes2 = await pdsAgent.api.com.atproto.admin.getSubjectStatus(
@@ -699,11 +578,10 @@ describe('moderation', () => {
699
578
  })
700
579
 
701
580
  it('fans out record takedowns', async () => {
702
- const post = sc.posts[sc.dids.bob][0]
703
- const uri = post.ref.uriStr
704
- const cid = post.ref.cidStr
705
- await performTakedown({
706
- content: { uri, cid },
581
+ const post = sc.posts[sc.dids.bob][0].ref
582
+ const uri = post.uriStr
583
+ await modClient.performTakedown({
584
+ subject: recordSubject(post),
707
585
  })
708
586
  await ozone.processAll()
709
587
 
@@ -723,7 +601,7 @@ describe('moderation', () => {
723
601
  expect(takedownLabel1).toBeDefined()
724
602
 
725
603
  // cleanup
726
- await performReverseTakedown({ content: { uri, cid } })
604
+ await modClient.performReverseTakedown({ subject: recordSubject(post) })
727
605
  await ozone.processAll()
728
606
 
729
607
  const pdsRes2 = await pdsAgent.api.com.atproto.admin.getSubjectStatus(
@@ -742,10 +620,10 @@ describe('moderation', () => {
742
620
  })
743
621
 
744
622
  it('allows full moderators to takedown.', async () => {
745
- await agent.api.com.atproto.admin.emitModerationEvent(
623
+ await modClient.emitEvent(
746
624
  {
747
625
  event: {
748
- $type: 'com.atproto.admin.defs#modEventTakedown',
626
+ $type: 'tools.ozone.moderation.defs#modEventTakedown',
749
627
  },
750
628
  createdBy: 'did:example:moderator',
751
629
  subject: {
@@ -753,10 +631,7 @@ describe('moderation', () => {
753
631
  did: sc.dids.bob,
754
632
  },
755
633
  },
756
- {
757
- encoding: 'application/json',
758
- headers: network.ozone.adminAuthHeaders('moderator'),
759
- },
634
+ 'moderator',
760
635
  )
761
636
  // cleanup
762
637
  await reverse({
@@ -768,47 +643,42 @@ describe('moderation', () => {
768
643
  })
769
644
 
770
645
  it('does not allow non-full moderators to takedown.', async () => {
771
- const attemptTakedownTriage =
772
- agent.api.com.atproto.admin.emitModerationEvent(
773
- {
774
- event: {
775
- $type: 'com.atproto.admin.defs#modEventTakedown',
776
- },
777
- createdBy: 'did:example:moderator',
778
- subject: {
779
- $type: 'com.atproto.admin.defs#repoRef',
780
- did: sc.dids.bob,
781
- },
646
+ const attemptTakedownTriage = modClient.emitEvent(
647
+ {
648
+ event: {
649
+ $type: 'tools.ozone.moderation.defs#modEventTakedown',
782
650
  },
783
- {
784
- encoding: 'application/json',
785
- headers: network.ozone.adminAuthHeaders('triage'),
651
+ createdBy: 'did:example:moderator',
652
+ subject: {
653
+ $type: 'com.atproto.admin.defs#repoRef',
654
+ did: sc.dids.bob,
786
655
  },
787
- )
656
+ },
657
+ 'triage',
658
+ )
788
659
  await expect(attemptTakedownTriage).rejects.toThrow(
789
660
  'Must be a full moderator to take this type of action',
790
661
  )
791
662
  })
792
663
 
793
664
  it('automatically reverses actions marked with duration', async () => {
794
- await createReport({
665
+ await sc.createReport({
795
666
  reasonType: REASONSPAM,
796
- account: sc.dids.bob,
797
- author: sc.dids.alice,
667
+ subject: repoSubject(sc.dids.bob),
668
+ reportedBy: sc.dids.alice,
798
669
  })
799
- const { data: action } = await performTakedown({
800
- account: sc.dids.bob,
670
+ const action = await modClient.performTakedown({
671
+ subject: repoSubject(sc.dids.bob),
801
672
  // Use negative value to set the expiry time in the past so that the action is automatically reversed
802
673
  // right away without having to wait n number of hours for a successful assertion
803
674
  durationInHours: -1,
804
675
  })
805
676
  await ozone.processAll()
806
677
 
807
- const { data: statusesAfterTakedown } =
808
- await agent.api.com.atproto.admin.queryModerationStatuses(
809
- { subject: sc.dids.bob },
810
- { headers: network.ozone.adminAuthHeaders('moderator') },
811
- )
678
+ const statusesAfterTakedown = await modClient.queryStatuses(
679
+ { subject: sc.dids.bob },
680
+ 'moderator',
681
+ )
812
682
 
813
683
  expect(statusesAfterTakedown.subjectStatuses[0]).toMatchObject({
814
684
  takendown: true,
@@ -822,15 +692,9 @@ describe('moderation', () => {
822
692
  await reverser.findAndRevertDueActions()
823
693
  await ozone.processAll()
824
694
 
825
- const [{ data: eventList }, { data: statuses }] = await Promise.all([
826
- agent.api.com.atproto.admin.queryModerationEvents(
827
- { subject: sc.dids.bob },
828
- { headers: network.ozone.adminAuthHeaders('moderator') },
829
- ),
830
- agent.api.com.atproto.admin.queryModerationStatuses(
831
- { subject: sc.dids.bob },
832
- { headers: network.ozone.adminAuthHeaders('moderator') },
833
- ),
695
+ const [eventList, statuses] = await Promise.all([
696
+ modClient.queryEvents({ subject: sc.dids.bob }, 'moderator'),
697
+ modClient.queryStatuses({ subject: sc.dids.bob }, 'moderator'),
834
698
  ])
835
699
 
836
700
  expect(statuses.subjectStatuses[0]).toMatchObject({
@@ -842,7 +706,7 @@ describe('moderation', () => {
842
706
  expect(eventList.events[0]).toMatchObject({
843
707
  createdBy: action.createdBy,
844
708
  event: {
845
- $type: 'com.atproto.admin.defs#modEventReverseTakedown',
709
+ $type: 'tools.ozone.moderation.defs#modEventReverseTakedown',
846
710
  comment:
847
711
  '[SCHEDULED_REVERSAL] Reverting action as originally scheduled',
848
712
  },
@@ -866,66 +730,54 @@ describe('moderation', () => {
866
730
  })
867
731
 
868
732
  async function emitLabelEvent(
869
- opts: Partial<ComAtprotoAdminEmitModerationEvent.InputSchema> & {
870
- subject: ComAtprotoAdminEmitModerationEvent.InputSchema['subject']
733
+ opts: Partial<ToolsOzoneModerationEmitEvent.InputSchema> & {
734
+ subject: ToolsOzoneModerationEmitEvent.InputSchema['subject']
871
735
  createLabelVals: ModEventLabel['createLabelVals']
872
736
  negateLabelVals: ModEventLabel['negateLabelVals']
873
737
  },
874
738
  ) {
875
739
  const { createLabelVals, negateLabelVals } = opts
876
- const result = await agent.api.com.atproto.admin.emitModerationEvent(
877
- {
878
- event: {
879
- $type: 'com.atproto.admin.defs#modEventLabel',
880
- createLabelVals,
881
- negateLabelVals,
882
- },
883
- createdBy: 'did:example:admin',
884
- reason: 'Y',
885
- ...opts,
886
- },
887
- {
888
- encoding: 'application/json',
889
- headers: network.ozone.adminAuthHeaders(),
740
+ const result = await modClient.emitEvent({
741
+ event: {
742
+ $type: 'tools.ozone.moderation.defs#modEventLabel',
743
+ createLabelVals,
744
+ negateLabelVals,
890
745
  },
891
- )
746
+ createdBy: 'did:example:admin',
747
+ reason: 'Y',
748
+ ...opts,
749
+ })
892
750
  return result.data
893
751
  }
894
752
 
895
753
  async function reverse(
896
- opts: Partial<ComAtprotoAdminEmitModerationEvent.InputSchema> & {
897
- subject: ComAtprotoAdminEmitModerationEvent.InputSchema['subject']
754
+ opts: Partial<ToolsOzoneModerationEmitEvent.InputSchema> & {
755
+ subject: ToolsOzoneModerationEmitEvent.InputSchema['subject']
898
756
  },
899
757
  ) {
900
- await agent.api.com.atproto.admin.emitModerationEvent(
901
- {
902
- event: {
903
- $type: 'com.atproto.admin.defs#modEventReverseTakedown',
904
- },
905
- createdBy: 'did:example:admin',
906
- reason: 'Y',
907
- ...opts,
908
- },
909
- {
910
- encoding: 'application/json',
911
- headers: network.ozone.adminAuthHeaders(),
758
+ await modClient.emitEvent({
759
+ event: {
760
+ $type: 'tools.ozone.moderation.defs#modEventReverseTakedown',
912
761
  },
913
- )
762
+ createdBy: 'did:example:admin',
763
+ reason: 'Y',
764
+ ...opts,
765
+ })
914
766
  }
915
767
 
916
768
  async function getRecordLabels(uri: string) {
917
- const result = await agent.api.com.atproto.admin.getRecord(
769
+ const result = await agent.api.tools.ozone.moderation.getRecord(
918
770
  { uri },
919
- { headers: network.ozone.adminAuthHeaders() },
771
+ { headers: await network.ozone.modHeaders() },
920
772
  )
921
773
  const labels = result.data.labels ?? []
922
774
  return labels.map((l) => l.val)
923
775
  }
924
776
 
925
777
  async function getRepoLabels(did: string) {
926
- const result = await agent.api.com.atproto.admin.getRepo(
778
+ const result = await agent.api.tools.ozone.moderation.getRepo(
927
779
  { did },
928
- { headers: network.ozone.adminAuthHeaders() },
780
+ { headers: await network.ozone.modHeaders() },
929
781
  )
930
782
  const labels = result.data.labels ?? []
931
783
  return labels.map((l) => l.val)
@@ -951,18 +803,15 @@ describe('moderation', () => {
951
803
  await fetch(imageUri)
952
804
  const cached = await fetch(imageUri)
953
805
  expect(cached.headers.get('x-cache')).toEqual('hit')
954
- await performTakedown({
955
- content: {
956
- uri: post.ref.uriStr,
957
- cid: post.ref.cidStr,
958
- },
806
+ await modClient.performTakedown({
807
+ subject: recordSubject(post.ref),
959
808
  subjectBlobCids: [blob.image.ref.toString()],
960
809
  })
961
810
  await ozone.processAll()
962
811
  })
963
812
 
964
813
  it('sets blobCids in moderation status', async () => {
965
- const { subjectStatuses } = await getStatuses({
814
+ const { subjectStatuses } = await modClient.queryStatuses({
966
815
  subject: post.ref.uriStr,
967
816
  })
968
817
 
@@ -1020,11 +869,8 @@ describe('moderation', () => {
1020
869
  })
1021
870
 
1022
871
  it('restores blob when action is reversed.', async () => {
1023
- await performReverseTakedown({
1024
- content: {
1025
- uri: post.ref.uriStr,
1026
- cid: post.ref.cidStr,
1027
- },
872
+ await modClient.performReverseTakedown({
873
+ subject: recordSubject(post.ref),
1028
874
  subjectBlobCids: [blob.image.ref.toString()],
1029
875
  })
1030
876