@atproto/ozone 0.0.16 → 0.0.17-next.0

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 (66) hide show
  1. package/dist/api/moderation/util.d.ts +1 -1
  2. package/dist/auth-verifier.d.ts +7 -11
  3. package/dist/config/config.d.ts +1 -0
  4. package/dist/config/env.d.ts +1 -2
  5. package/dist/config/secrets.d.ts +0 -2
  6. package/dist/daemon/event-pusher.d.ts +2 -0
  7. package/dist/db/index.js.map +1 -1
  8. package/dist/db/schema/moderation_subject_status.d.ts +2 -2
  9. package/dist/index.js +821 -1055
  10. package/dist/index.js.map +3 -3
  11. package/dist/lexicon/index.d.ts +8 -0
  12. package/dist/lexicon/lexicons.d.ts +298 -0
  13. package/dist/lexicon/types/app/bsky/actor/defs.d.ts +23 -1
  14. package/dist/lexicon/types/app/bsky/embed/record.d.ts +2 -1
  15. package/dist/lexicon/types/app/bsky/labeler/defs.d.ts +41 -0
  16. package/dist/lexicon/types/app/bsky/labeler/getServices.d.ts +36 -0
  17. package/dist/lexicon/types/app/bsky/labeler/service.d.ts +14 -0
  18. package/dist/lexicon/types/com/atproto/admin/defs.d.ts +2 -1
  19. package/dist/lexicon/types/com/atproto/label/defs.d.ts +18 -0
  20. package/dist/mod-service/index.d.ts +2 -2
  21. package/package.json +5 -4
  22. package/src/api/admin/createCommunicationTemplate.ts +1 -1
  23. package/src/api/admin/deleteCommunicationTemplate.ts +1 -1
  24. package/src/api/admin/emitModerationEvent.ts +6 -2
  25. package/src/api/admin/getModerationEvent.ts +1 -1
  26. package/src/api/admin/getRecord.ts +1 -1
  27. package/src/api/admin/getRepo.ts +1 -1
  28. package/src/api/admin/listCommunicationTemplates.ts +1 -1
  29. package/src/api/admin/queryModerationEvents.ts +1 -1
  30. package/src/api/admin/queryModerationStatuses.ts +1 -1
  31. package/src/api/admin/searchRepos.ts +1 -1
  32. package/src/api/admin/updateCommunicationTemplate.ts +1 -1
  33. package/src/api/admin/util.ts +1 -1
  34. package/src/api/moderation/createReport.ts +1 -2
  35. package/src/api/proxied.ts +8 -8
  36. package/src/api/temp/fetchLabels.ts +1 -1
  37. package/src/auth-verifier.ts +19 -29
  38. package/src/config/config.ts +10 -7
  39. package/src/config/env.ts +2 -4
  40. package/src/config/secrets.ts +0 -6
  41. package/src/context.ts +1 -3
  42. package/src/daemon/context.ts +2 -2
  43. package/src/daemon/event-pusher.ts +9 -1
  44. package/src/db/schema/moderation_subject_status.ts +6 -1
  45. package/src/lexicon/index.ts +23 -0
  46. package/src/lexicon/lexicons.ts +327 -1
  47. package/src/lexicon/types/app/bsky/actor/defs.ts +57 -1
  48. package/src/lexicon/types/app/bsky/embed/record.ts +2 -0
  49. package/src/lexicon/types/app/bsky/labeler/defs.ts +93 -0
  50. package/src/lexicon/types/app/bsky/labeler/getServices.ts +51 -0
  51. package/src/lexicon/types/app/bsky/labeler/service.ts +31 -0
  52. package/src/lexicon/types/com/atproto/admin/defs.ts +3 -0
  53. package/src/lexicon/types/com/atproto/label/defs.ts +68 -0
  54. package/src/mod-service/index.ts +4 -3
  55. package/src/mod-service/status.ts +42 -26
  56. package/tests/__snapshots__/get-record.test.ts.snap +4 -4
  57. package/tests/__snapshots__/get-repo.test.ts.snap +2 -2
  58. package/tests/communication-templates.test.ts +7 -7
  59. package/tests/get-record.test.ts +17 -7
  60. package/tests/get-repo.test.ts +24 -12
  61. package/tests/moderation-appeals.test.ts +24 -52
  62. package/tests/moderation-events.test.ts +87 -130
  63. package/tests/moderation-status-tags.test.ts +16 -31
  64. package/tests/moderation-statuses.test.ts +125 -58
  65. package/tests/moderation.test.ts +140 -287
  66. package/tests/repo-search.test.ts +11 -4
@@ -1,9 +1,10 @@
1
- import { TestNetwork, SeedClient, basicSeed } from '@atproto/dev-env'
2
- import AtpAgent, {
3
- ComAtprotoAdminDefs,
4
- ComAtprotoAdminEmitModerationEvent,
5
- ComAtprotoAdminQueryModerationStatuses,
6
- } from '@atproto/api'
1
+ import {
2
+ TestNetwork,
3
+ SeedClient,
4
+ basicSeed,
5
+ ModeratorClient,
6
+ } from '@atproto/dev-env'
7
+ import { ComAtprotoAdminDefs } from '@atproto/api'
7
8
  import {
8
9
  REASONMISLEADING,
9
10
  REASONSPAM,
@@ -17,33 +18,15 @@ import { REVIEWESCALATED } from '../src/lexicon/types/com/atproto/admin/defs'
17
18
 
18
19
  describe('moderation-appeals', () => {
19
20
  let network: TestNetwork
20
- let agent: AtpAgent
21
- let pdsAgent: AtpAgent
22
21
  let sc: SeedClient
23
-
24
- const emitModerationEvent = async (
25
- eventData: ComAtprotoAdminEmitModerationEvent.InputSchema,
26
- ) => {
27
- return pdsAgent.api.com.atproto.admin.emitModerationEvent(eventData, {
28
- encoding: 'application/json',
29
- headers: network.ozone.adminAuthHeaders('moderator'),
30
- })
31
- }
32
-
33
- const queryModerationStatuses = (
34
- statusQuery: ComAtprotoAdminQueryModerationStatuses.QueryParams,
35
- ) =>
36
- agent.api.com.atproto.admin.queryModerationStatuses(statusQuery, {
37
- headers: network.ozone.adminAuthHeaders('moderator'),
38
- })
22
+ let modClient: ModeratorClient
39
23
 
40
24
  beforeAll(async () => {
41
25
  network = await TestNetwork.create({
42
26
  dbPostgresSchema: 'ozone_moderation_appeals',
43
27
  })
44
- agent = network.ozone.getClient()
45
- pdsAgent = network.pds.getClient()
46
28
  sc = network.getSeedClient()
29
+ modClient = network.ozone.getModClient()
47
30
  await basicSeed(sc)
48
31
  await network.processAll()
49
32
  })
@@ -57,12 +40,12 @@ describe('moderation-appeals', () => {
57
40
  status: string,
58
41
  appealed: boolean | undefined,
59
42
  ): Promise<ComAtprotoAdminDefs.SubjectStatusView | undefined> => {
60
- const { data } = await queryModerationStatuses({
43
+ const res = await modClient.queryModerationStatuses({
61
44
  subject,
62
45
  })
63
- expect(data.subjectStatuses[0]?.reviewState).toEqual(status)
64
- expect(data.subjectStatuses[0]?.appealed).toEqual(appealed)
65
- return data.subjectStatuses[0]
46
+ expect(res.subjectStatuses[0]?.reviewState).toEqual(status)
47
+ expect(res.subjectStatuses[0]?.appealed).toEqual(appealed)
48
+ return res.subjectStatuses[0]
66
49
  }
67
50
 
68
51
  describe('appeals from users', () => {
@@ -83,13 +66,12 @@ describe('moderation-appeals', () => {
83
66
 
84
67
  it('only changes subject status if original author of the content or a moderator is appealing', async () => {
85
68
  // Create a report by alice
86
- await emitModerationEvent({
69
+ await modClient.emitModerationEvent({
87
70
  event: {
88
71
  $type: 'com.atproto.admin.defs#modEventReport',
89
72
  reportType: REASONMISLEADING,
90
73
  },
91
74
  subject: getBobsPostSubject(),
92
- createdBy: sc.dids.alice,
93
75
  })
94
76
 
95
77
  await assertBobsPostStatus(REVIEWOPEN, undefined)
@@ -108,13 +90,12 @@ describe('moderation-appeals', () => {
108
90
  await assertBobsPostStatus(REVIEWOPEN, undefined)
109
91
 
110
92
  // Emit report event as moderator
111
- await emitModerationEvent({
93
+ await modClient.emitModerationEvent({
112
94
  event: {
113
95
  $type: 'com.atproto.admin.defs#modEventReport',
114
96
  reportType: REASONAPPEAL,
115
97
  },
116
98
  subject: getBobsPostSubject(),
117
- createdBy: sc.dids.alice,
118
99
  })
119
100
 
120
101
  // Verify that appeal status changed when appeal report was emitted by moderator
@@ -151,23 +132,21 @@ describe('moderation-appeals', () => {
151
132
  })
152
133
  it('allows multiple appeals and updates last appealed timestamp', async () => {
153
134
  // Resolve appeal with acknowledge
154
- await emitModerationEvent({
135
+ await modClient.emitModerationEvent({
155
136
  event: {
156
137
  $type: 'com.atproto.admin.defs#modEventResolveAppeal',
157
138
  },
158
139
  subject: getBobsPostSubject(),
159
- createdBy: sc.dids.carol,
160
140
  })
161
141
 
162
142
  const previousStatus = await assertBobsPostStatus(REVIEWESCALATED, false)
163
143
 
164
- await emitModerationEvent({
144
+ await modClient.emitModerationEvent({
165
145
  event: {
166
146
  $type: 'com.atproto.admin.defs#modEventReport',
167
147
  reportType: REASONAPPEAL,
168
148
  },
169
149
  subject: getBobsPostSubject(),
170
- createdBy: sc.dids.bob,
171
150
  })
172
151
 
173
152
  // Verify that even after the appeal event by bob for his post, the appeal status is true again with new timestamp
@@ -186,32 +165,29 @@ describe('moderation-appeals', () => {
186
165
  })
187
166
  it('appeal status is maintained while review state changes based on incoming events', async () => {
188
167
  // Bob reports alice's post
189
- await emitModerationEvent({
168
+ await modClient.emitModerationEvent({
190
169
  event: {
191
170
  $type: 'com.atproto.admin.defs#modEventReport',
192
171
  reportType: REASONMISLEADING,
193
172
  },
194
173
  subject: getAlicesPostSubject(),
195
- createdBy: sc.dids.bob,
196
174
  })
197
175
 
198
176
  // Moderator acknowledges the report, assume a label was applied too
199
- await emitModerationEvent({
177
+ await modClient.emitModerationEvent({
200
178
  event: {
201
179
  $type: 'com.atproto.admin.defs#modEventAcknowledge',
202
180
  },
203
181
  subject: getAlicesPostSubject(),
204
- createdBy: sc.dids.carol,
205
182
  })
206
183
 
207
184
  // Alice appeals the report
208
- await emitModerationEvent({
185
+ await modClient.emitModerationEvent({
209
186
  event: {
210
187
  $type: 'com.atproto.admin.defs#modEventReport',
211
188
  reportType: REASONAPPEAL,
212
189
  },
213
190
  subject: getAlicesPostSubject(),
214
- createdBy: sc.dids.alice,
215
191
  })
216
192
 
217
193
  await assertSubjectStatus(
@@ -221,13 +197,12 @@ describe('moderation-appeals', () => {
221
197
  )
222
198
 
223
199
  // Bob reports it again
224
- await emitModerationEvent({
200
+ await modClient.emitModerationEvent({
225
201
  event: {
226
202
  $type: 'com.atproto.admin.defs#modEventReport',
227
203
  reportType: REASONSPAM,
228
204
  },
229
205
  subject: getAlicesPostSubject(),
230
- createdBy: sc.dids.bob,
231
206
  })
232
207
 
233
208
  // Assert that the status is still REVIEWESCALATED, as report events are meant to do
@@ -238,12 +213,11 @@ describe('moderation-appeals', () => {
238
213
  )
239
214
 
240
215
  // Emit an escalation event
241
- await emitModerationEvent({
216
+ await modClient.emitModerationEvent({
242
217
  event: {
243
218
  $type: 'com.atproto.admin.defs#modEventEscalate',
244
219
  },
245
220
  subject: getAlicesPostSubject(),
246
- createdBy: sc.dids.carol,
247
221
  })
248
222
 
249
223
  await assertSubjectStatus(
@@ -253,25 +227,23 @@ describe('moderation-appeals', () => {
253
227
  )
254
228
 
255
229
  // Emit an acknowledge event
256
- await emitModerationEvent({
230
+ await modClient.emitModerationEvent({
257
231
  event: {
258
232
  $type: 'com.atproto.admin.defs#modEventAcknowledge',
259
233
  },
260
234
  subject: getAlicesPostSubject(),
261
- createdBy: sc.dids.carol,
262
235
  })
263
236
 
264
237
  // Assert that status moved on to reviewClosed while appealed status is still true
265
238
  await assertSubjectStatus(getAlicesPostSubject().uri, REVIEWCLOSED, true)
266
239
 
267
240
  // Emit a resolveAppeal event
268
- await emitModerationEvent({
241
+ await modClient.emitModerationEvent({
269
242
  event: {
270
243
  $type: 'com.atproto.admin.defs#modEventResolveAppeal',
271
244
  comment: 'lgtm',
272
245
  },
273
246
  subject: getAlicesPostSubject(),
274
- createdBy: sc.dids.carol,
275
247
  })
276
248
 
277
249
  // Assert that status stayed the same while appealed status is still true
@@ -1,11 +1,13 @@
1
1
  import assert from 'node:assert'
2
2
  import EventEmitter, { once } from 'node:events'
3
+ import {
4
+ TestNetwork,
5
+ SeedClient,
6
+ basicSeed,
7
+ ModeratorClient,
8
+ } from '@atproto/dev-env'
9
+ import { ComAtprotoAdminDefs } from '@atproto/api'
3
10
  import Mail from 'nodemailer/lib/mailer'
4
- import { TestNetwork, SeedClient, basicSeed } from '@atproto/dev-env'
5
- import AtpAgent, {
6
- ComAtprotoAdminDefs,
7
- ComAtprotoAdminEmitModerationEvent,
8
- } from '@atproto/api'
9
11
  import { forSnapshot } from './_util'
10
12
  import {
11
13
  REASONAPPEAL,
@@ -15,23 +17,8 @@ import {
15
17
 
16
18
  describe('moderation-events', () => {
17
19
  let network: TestNetwork
18
- let agent: AtpAgent
19
- let pdsAgent: AtpAgent
20
20
  let sc: SeedClient
21
-
22
- const emitModerationEvent = async (
23
- eventData: ComAtprotoAdminEmitModerationEvent.InputSchema,
24
- ) => {
25
- return pdsAgent.api.com.atproto.admin.emitModerationEvent(eventData, {
26
- encoding: 'application/json',
27
- headers: network.ozone.adminAuthHeaders('moderator'),
28
- })
29
- }
30
-
31
- const queryModerationEvents = (eventQuery) =>
32
- agent.api.com.atproto.admin.queryModerationEvents(eventQuery, {
33
- headers: network.ozone.adminAuthHeaders('moderator'),
34
- })
21
+ let modClient: ModeratorClient
35
22
 
36
23
  const seedEvents = async () => {
37
24
  const bobsAccount = {
@@ -54,25 +41,19 @@ describe('moderation-events', () => {
54
41
  }
55
42
 
56
43
  for (let i = 0; i < 4; i++) {
57
- await emitModerationEvent({
58
- event: {
59
- $type: 'com.atproto.admin.defs#modEventReport',
60
- reportType: i % 2 ? REASONSPAM : REASONMISLEADING,
61
- comment: 'X',
62
- },
44
+ await sc.createReport({
45
+ reasonType: i % 2 ? REASONSPAM : REASONMISLEADING,
46
+ reason: 'X',
63
47
  // Report bob's account by alice and vice versa
64
48
  subject: i % 2 ? bobsAccount : alicesAccount,
65
- createdBy: i % 2 ? sc.dids.alice : sc.dids.bob,
49
+ reportedBy: i % 2 ? sc.dids.alice : sc.dids.bob,
66
50
  })
67
- await emitModerationEvent({
68
- event: {
69
- $type: 'com.atproto.admin.defs#modEventReport',
70
- reportType: REASONSPAM,
71
- comment: 'X',
72
- },
51
+ await sc.createReport({
52
+ reasonType: REASONSPAM,
53
+ reason: 'X',
73
54
  // Report bob's post by alice and vice versa
74
55
  subject: i % 2 ? bobsPost : alicesPost,
75
- createdBy: i % 2 ? sc.dids.alice : sc.dids.bob,
56
+ reportedBy: i % 2 ? sc.dids.alice : sc.dids.bob,
76
57
  })
77
58
  }
78
59
  }
@@ -81,9 +62,8 @@ describe('moderation-events', () => {
81
62
  network = await TestNetwork.create({
82
63
  dbPostgresSchema: 'ozone_moderation_events',
83
64
  })
84
- agent = network.ozone.getClient()
85
- pdsAgent = network.pds.getClient()
86
65
  sc = network.getSeedClient()
66
+ modClient = network.ozone.getModClient()
87
67
  await basicSeed(sc)
88
68
  await network.processAll()
89
69
  await seedEvents()
@@ -96,16 +76,16 @@ describe('moderation-events', () => {
96
76
  describe('query events', () => {
97
77
  it('returns all events for record or repo', async () => {
98
78
  const [bobsEvents, alicesPostEvents] = await Promise.all([
99
- queryModerationEvents({
79
+ modClient.queryModerationEvents({
100
80
  subject: sc.dids.bob,
101
81
  }),
102
- queryModerationEvents({
82
+ modClient.queryModerationEvents({
103
83
  subject: sc.posts[sc.dids.alice][0].ref.uriStr,
104
84
  }),
105
85
  ])
106
86
 
107
- expect(forSnapshot(bobsEvents.data.events)).toMatchSnapshot()
108
- expect(forSnapshot(alicesPostEvents.data.events)).toMatchSnapshot()
87
+ expect(forSnapshot(bobsEvents.events)).toMatchSnapshot()
88
+ expect(forSnapshot(alicesPostEvents.events)).toMatchSnapshot()
109
89
  })
110
90
 
111
91
  it('filters events by types', async () => {
@@ -114,66 +94,64 @@ describe('moderation-events', () => {
114
94
  did: sc.dids.alice,
115
95
  }
116
96
  await Promise.all([
117
- emitModerationEvent({
97
+ modClient.emitModerationEvent({
118
98
  event: {
119
99
  $type: 'com.atproto.admin.defs#modEventComment',
120
100
  comment: 'X',
121
101
  },
122
102
  subject: alicesAccount,
123
- createdBy: 'did:plc:moderator',
124
103
  }),
125
- emitModerationEvent({
104
+ modClient.emitModerationEvent({
126
105
  event: {
127
106
  $type: 'com.atproto.admin.defs#modEventEscalate',
128
107
  comment: 'X',
129
108
  },
130
109
  subject: alicesAccount,
131
- createdBy: 'did:plc:moderator',
132
110
  }),
133
111
  ])
134
112
  const [allEvents, reportEvents] = await Promise.all([
135
- queryModerationEvents({
113
+ modClient.queryModerationEvents({
136
114
  subject: sc.dids.alice,
137
115
  }),
138
- queryModerationEvents({
116
+ modClient.queryModerationEvents({
139
117
  subject: sc.dids.alice,
140
118
  types: ['com.atproto.admin.defs#modEventReport'],
141
119
  }),
142
120
  ])
143
121
 
144
- expect(allEvents.data.events.length).toBeGreaterThan(
145
- reportEvents.data.events.length,
122
+ expect(allEvents.events.length).toBeGreaterThan(
123
+ reportEvents.events.length,
146
124
  )
147
125
  expect(
148
- [...new Set(reportEvents.data.events.map((e) => e.event.$type))].length,
126
+ [...new Set(reportEvents.events.map((e) => e.event.$type))].length,
149
127
  ).toEqual(1)
150
128
 
151
129
  expect(
152
- [...new Set(allEvents.data.events.map((e) => e.event.$type))].length,
130
+ [...new Set(allEvents.events.map((e) => e.event.$type))].length,
153
131
  ).toEqual(4)
154
132
  })
155
133
 
156
134
  it('returns events for all content by user', async () => {
157
135
  const [forAccount, forPost] = await Promise.all([
158
- queryModerationEvents({
136
+ modClient.queryModerationEvents({
159
137
  subject: sc.dids.bob,
160
138
  includeAllUserRecords: true,
161
139
  }),
162
- queryModerationEvents({
140
+ modClient.queryModerationEvents({
163
141
  subject: sc.posts[sc.dids.bob][0].ref.uriStr,
164
142
  includeAllUserRecords: true,
165
143
  }),
166
144
  ])
167
145
 
168
- expect(forAccount.data.events.length).toEqual(forPost.data.events.length)
146
+ expect(forAccount.events.length).toEqual(forPost.events.length)
169
147
  // Save events are returned from both requests
170
- expect(forPost.data.events.map(({ id }) => id).sort()).toEqual(
171
- forAccount.data.events.map(({ id }) => id).sort(),
148
+ expect(forPost.events.map(({ id }) => id).sort()).toEqual(
149
+ forAccount.events.map(({ id }) => id).sort(),
172
150
  )
173
151
  })
174
152
 
175
153
  it('returns paginated list of events with cursor', async () => {
176
- const allEvents = await queryModerationEvents({
154
+ const allEvents = await modClient.queryModerationEvents({
177
155
  subject: sc.dids.bob,
178
156
  includeAllUserRecords: true,
179
157
  })
@@ -186,15 +164,15 @@ describe('moderation-events', () => {
186
164
  let count = 0
187
165
  do {
188
166
  // get 1 event at a time and check we get all events
189
- const { data } = await queryModerationEvents({
167
+ const res = await modClient.queryModerationEvents({
190
168
  limit: 1,
191
169
  subject: sc.dids.bob,
192
170
  includeAllUserRecords: true,
193
171
  cursor: defaultCursor,
194
172
  sortDirection,
195
173
  })
196
- events.push(...data.events)
197
- defaultCursor = data.cursor
174
+ events.push(...res.events)
175
+ defaultCursor = res.cursor
198
176
  count++
199
177
  // The count is a circuit breaker to prevent infinite loop in case of failing test
200
178
  } while (defaultCursor && count < 10)
@@ -205,49 +183,51 @@ describe('moderation-events', () => {
205
183
  const defaultEvents = await getPaginatedEvents()
206
184
  const reversedEvents = await getPaginatedEvents('asc')
207
185
 
208
- expect(allEvents.data.events.length).toEqual(6)
209
- expect(defaultEvents.length).toEqual(allEvents.data.events.length)
210
- expect(reversedEvents.length).toEqual(allEvents.data.events.length)
186
+ expect(allEvents.events.length).toEqual(6)
187
+ expect(defaultEvents.length).toEqual(allEvents.events.length)
188
+ expect(reversedEvents.length).toEqual(allEvents.events.length)
211
189
  // First event in the reversed list is the last item in the default list
212
- expect(reversedEvents[0].id).toEqual(defaultEvents[5].id)
190
+ expect(reversedEvents[0].id).toEqual(
191
+ defaultEvents[defaultEvents.length - 1].id,
192
+ )
213
193
  })
214
194
 
215
195
  it('returns report events matching reportType filters', async () => {
216
196
  const [spamEvents, misleadingEvents] = await Promise.all([
217
- queryModerationEvents({
197
+ modClient.queryModerationEvents({
218
198
  reportTypes: [REASONSPAM],
219
199
  }),
220
- queryModerationEvents({
200
+ modClient.queryModerationEvents({
221
201
  reportTypes: [REASONMISLEADING, REASONAPPEAL],
222
202
  }),
223
203
  ])
224
204
 
225
- expect(misleadingEvents.data.events.length).toEqual(2)
226
- expect(spamEvents.data.events.length).toEqual(6)
205
+ expect(misleadingEvents.events.length).toEqual(2)
206
+ expect(spamEvents.events.length).toEqual(6)
227
207
  })
228
208
 
229
209
  it('returns events matching keyword in comment', async () => {
230
210
  const [eventsWithX, eventsWithTest, eventsWithComment] =
231
211
  await Promise.all([
232
- queryModerationEvents({
212
+ modClient.queryModerationEvents({
233
213
  comment: 'X',
234
214
  }),
235
- queryModerationEvents({
215
+ modClient.queryModerationEvents({
236
216
  comment: 'test',
237
217
  }),
238
- queryModerationEvents({
218
+ modClient.queryModerationEvents({
239
219
  hasComment: true,
240
220
  }),
241
221
  ])
242
222
 
243
- expect(eventsWithX.data.events.length).toEqual(10)
244
- expect(eventsWithTest.data.events.length).toEqual(0)
245
- expect(eventsWithComment.data.events.length).toEqual(10)
223
+ expect(eventsWithX.events.length).toEqual(10)
224
+ expect(eventsWithTest.events.length).toEqual(0)
225
+ expect(eventsWithComment.events.length).toEqual(10)
246
226
  })
247
227
 
248
228
  it('returns events matching filter params for labels', async () => {
249
229
  const [negatedLabelEvent, createdLabelEvent] = await Promise.all([
250
- emitModerationEvent({
230
+ modClient.emitModerationEvent({
251
231
  event: {
252
232
  $type: 'com.atproto.admin.defs#modEventLabel',
253
233
  comment: 'X',
@@ -259,9 +239,8 @@ describe('moderation-events', () => {
259
239
  $type: 'com.atproto.admin.defs#repoRef',
260
240
  did: sc.dids.alice,
261
241
  },
262
- createdBy: sc.dids.bob,
263
242
  }),
264
- emitModerationEvent({
243
+ modClient.emitModerationEvent({
265
244
  event: {
266
245
  $type: 'com.atproto.admin.defs#modEventLabel',
267
246
  comment: 'X',
@@ -273,36 +252,31 @@ describe('moderation-events', () => {
273
252
  $type: 'com.atproto.admin.defs#repoRef',
274
253
  did: sc.dids.bob,
275
254
  },
276
- createdBy: sc.dids.alice,
277
255
  }),
278
256
  ])
279
257
  const [withTwoLabels, withoutTwoLabels, withOneLabel, withoutOneLabel] =
280
258
  await Promise.all([
281
- queryModerationEvents({
259
+ modClient.queryModerationEvents({
282
260
  addedLabels: ['L1', 'L3'],
283
261
  }),
284
- queryModerationEvents({
262
+ modClient.queryModerationEvents({
285
263
  removedLabels: ['L1', 'L2'],
286
264
  }),
287
- queryModerationEvents({
265
+ modClient.queryModerationEvents({
288
266
  addedLabels: ['L1'],
289
267
  }),
290
- queryModerationEvents({
268
+ modClient.queryModerationEvents({
291
269
  removedLabels: ['L2'],
292
270
  }),
293
271
  ])
294
272
 
295
273
  // Verify that when querying for events where 2 different labels were added
296
274
  // events where all of the labels from the list was added are returned
297
- expect(withTwoLabels.data.events.length).toEqual(0)
298
- expect(negatedLabelEvent.data.id).toEqual(
299
- withoutTwoLabels.data.events[0].id,
300
- )
275
+ expect(withTwoLabels.events.length).toEqual(0)
276
+ expect(negatedLabelEvent.id).toEqual(withoutTwoLabels.events[0].id)
301
277
 
302
- expect(createdLabelEvent.data.id).toEqual(withOneLabel.data.events[0].id)
303
- expect(negatedLabelEvent.data.id).toEqual(
304
- withoutOneLabel.data.events[0].id,
305
- )
278
+ expect(createdLabelEvent.id).toEqual(withOneLabel.events[0].id)
279
+ expect(negatedLabelEvent.id).toEqual(withoutOneLabel.events[0].id)
306
280
  })
307
281
  it('returns events matching filter params for tags', async () => {
308
282
  const tagEvent = async ({
@@ -312,7 +286,7 @@ describe('moderation-events', () => {
312
286
  add: string[]
313
287
  remove: string[]
314
288
  }) =>
315
- emitModerationEvent({
289
+ modClient.emitModerationEvent({
316
290
  event: {
317
291
  $type: 'com.atproto.admin.defs#modEventTag',
318
292
  comment: 'X',
@@ -323,43 +297,35 @@ describe('moderation-events', () => {
323
297
  $type: 'com.atproto.admin.defs#repoRef',
324
298
  did: sc.dids.carol,
325
299
  },
326
- createdBy: sc.dids.bob,
327
300
  })
328
301
  const addEvent = await tagEvent({ add: ['L1', 'L2'], remove: [] })
329
302
  const addAndRemoveEvent = await tagEvent({ add: ['L3'], remove: ['L2'] })
330
303
  const [addFinder, addAndRemoveFinder, _removeFinder] = await Promise.all([
331
- queryModerationEvents({
304
+ modClient.queryModerationEvents({
332
305
  addedTags: ['L1'],
333
306
  }),
334
- queryModerationEvents({
307
+ modClient.queryModerationEvents({
335
308
  addedTags: ['L3'],
336
309
  removedTags: ['L2'],
337
310
  }),
338
- queryModerationEvents({
311
+ modClient.queryModerationEvents({
339
312
  removedTags: ['L2'],
340
313
  }),
341
314
  ])
342
315
 
343
- expect(addFinder.data.events.length).toEqual(1)
344
- expect(addEvent.data.id).toEqual(addFinder.data.events[0].id)
316
+ expect(addFinder.events.length).toEqual(1)
317
+ expect(addEvent.id).toEqual(addFinder.events[0].id)
345
318
 
346
- expect(addAndRemoveEvent.data.id).toEqual(
347
- addAndRemoveFinder.data.events[0].id,
348
- )
349
- expect(addAndRemoveEvent.data.id).toEqual(
350
- addAndRemoveFinder.data.events[0].id,
351
- )
352
- expect(addAndRemoveEvent.data.event.add).toEqual(['L3'])
353
- expect(addAndRemoveEvent.data.event.remove).toEqual(['L2'])
319
+ expect(addAndRemoveEvent.id).toEqual(addAndRemoveFinder.events[0].id)
320
+ expect(addAndRemoveEvent.id).toEqual(addAndRemoveFinder.events[0].id)
321
+ expect(addAndRemoveEvent.event.add).toEqual(['L3'])
322
+ expect(addAndRemoveEvent.event.remove).toEqual(['L2'])
354
323
  })
355
324
  })
356
325
 
357
326
  describe('get event', () => {
358
327
  it('gets an event by specific id', async () => {
359
- const { data } = await pdsAgent.api.com.atproto.admin.getModerationEvent(
360
- { id: 1 },
361
- { headers: network.ozone.adminAuthHeaders('moderator') },
362
- )
328
+ const data = await modClient.getEvent(1)
363
329
  expect(forSnapshot(data)).toMatchSnapshot()
364
330
  })
365
331
  })
@@ -368,7 +334,7 @@ describe('moderation-events', () => {
368
334
  it('are tracked on takedown event', async () => {
369
335
  const post = sc.posts[sc.dids.carol][0]
370
336
  assert(post.images.length > 1)
371
- await emitModerationEvent({
337
+ await modClient.emitModerationEvent({
372
338
  event: {
373
339
  $type: 'com.atproto.admin.defs#modEventTakedown',
374
340
  },
@@ -378,18 +344,13 @@ describe('moderation-events', () => {
378
344
  cid: post.ref.cidStr,
379
345
  },
380
346
  subjectBlobCids: [post.images[0].image.ref.toString()],
381
- createdBy: sc.dids.alice,
382
347
  })
383
- const { data: result } =
384
- await pdsAgent.api.com.atproto.admin.queryModerationEvents(
385
- {
386
- subject: post.ref.uriStr,
387
- types: ['com.atproto.admin.defs#modEventTakedown'],
388
- },
389
- { headers: network.ozone.adminAuthHeaders('moderator') },
390
- )
348
+ const result = await modClient.queryModerationEvents({
349
+ subject: post.ref.uriStr,
350
+ types: ['com.atproto.admin.defs#modEventTakedown'],
351
+ })
391
352
  expect(result.events[0]).toMatchObject({
392
- createdBy: sc.dids.alice,
353
+ createdBy: network.ozone.moderatorAccnt.did,
393
354
  event: {
394
355
  $type: 'com.atproto.admin.defs#modEventTakedown',
395
356
  },
@@ -399,7 +360,7 @@ describe('moderation-events', () => {
399
360
 
400
361
  it("are tracked on reverse-takedown event even if they aren't specified", async () => {
401
362
  const post = sc.posts[sc.dids.carol][0]
402
- await emitModerationEvent({
363
+ await modClient.emitModerationEvent({
403
364
  event: {
404
365
  $type: 'com.atproto.admin.defs#modEventReverseTakedown',
405
366
  },
@@ -408,15 +369,12 @@ describe('moderation-events', () => {
408
369
  uri: post.ref.uriStr,
409
370
  cid: post.ref.cidStr,
410
371
  },
411
- createdBy: sc.dids.alice,
412
372
  })
413
- const { data: result } =
414
- await pdsAgent.api.com.atproto.admin.queryModerationEvents(
415
- { subject: post.ref.uriStr },
416
- { headers: network.ozone.adminAuthHeaders('moderator') },
417
- )
373
+ const result = await modClient.queryModerationEvents({
374
+ subject: post.ref.uriStr,
375
+ })
418
376
  expect(result.events[0]).toMatchObject({
419
- createdBy: sc.dids.alice,
377
+ createdBy: network.ozone.moderatorAccnt.did,
420
378
  event: {
421
379
  $type: 'com.atproto.admin.defs#modEventReverseTakedown',
422
380
  },
@@ -450,7 +408,7 @@ describe('moderation-events', () => {
450
408
 
451
409
  it('sends email via pds.', async () => {
452
410
  const mail = await getMailFrom(
453
- emitModerationEvent({
411
+ modClient.emitModerationEvent({
454
412
  event: {
455
413
  $type: 'com.atproto.admin.defs#modEventEmail',
456
414
  comment: 'Reaching out to Alice',
@@ -461,7 +419,6 @@ describe('moderation-events', () => {
461
419
  $type: 'com.atproto.admin.defs#repoRef',
462
420
  did: sc.dids.alice,
463
421
  },
464
- createdBy: sc.dids.bob,
465
422
  }),
466
423
  )
467
424
  expect(mail).toEqual({