@atproto/ozone 0.2.9 → 0.2.11

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 (306) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/package.json +25 -21
  3. package/bin/migration-create.ts +0 -38
  4. package/jest.config.cjs +0 -22
  5. package/src/api/chat/getActorMetadata.ts +0 -23
  6. package/src/api/chat/getConvo.ts +0 -23
  7. package/src/api/chat/getConvoMembers.ts +0 -23
  8. package/src/api/chat/getConvos.ts +0 -23
  9. package/src/api/chat/getMessageContext.ts +0 -42
  10. package/src/api/chat/index.ts +0 -16
  11. package/src/api/communication/createTemplate.ts +0 -51
  12. package/src/api/communication/deleteTemplate.ts +0 -23
  13. package/src/api/communication/listTemplates.ts +0 -31
  14. package/src/api/communication/updateTemplate.ts +0 -51
  15. package/src/api/health.ts +0 -27
  16. package/src/api/index.ts +0 -146
  17. package/src/api/label/fetchLabels.ts +0 -32
  18. package/src/api/label/queryLabels.ts +0 -57
  19. package/src/api/label/subscribeLabels.ts +0 -25
  20. package/src/api/moderation/cancelScheduledActions.ts +0 -72
  21. package/src/api/moderation/emitEvent.ts +0 -475
  22. package/src/api/moderation/getAccountTimeline.ts +0 -160
  23. package/src/api/moderation/getEvent.ts +0 -19
  24. package/src/api/moderation/getRecord.ts +0 -40
  25. package/src/api/moderation/getRecords.ts +0 -50
  26. package/src/api/moderation/getRepo.ts +0 -34
  27. package/src/api/moderation/getReporterStats.ts +0 -18
  28. package/src/api/moderation/getRepos.ts +0 -41
  29. package/src/api/moderation/getSubjects.ts +0 -101
  30. package/src/api/moderation/listScheduledActions.ts +0 -45
  31. package/src/api/moderation/queryEvents.ts +0 -72
  32. package/src/api/moderation/queryStatuses.ts +0 -23
  33. package/src/api/moderation/scheduleAction.ts +0 -129
  34. package/src/api/moderation/searchRepos.ts +0 -46
  35. package/src/api/moderation/util.ts +0 -96
  36. package/src/api/proxied.ts +0 -327
  37. package/src/api/queue/assignModerator.ts +0 -31
  38. package/src/api/queue/createQueue.ts +0 -62
  39. package/src/api/queue/deleteQueue.ts +0 -56
  40. package/src/api/queue/getAssignments.ts +0 -19
  41. package/src/api/queue/listQueues.ts +0 -39
  42. package/src/api/queue/routeReports.ts +0 -44
  43. package/src/api/queue/unassignModerator.ts +0 -26
  44. package/src/api/queue/updateQueue.ts +0 -54
  45. package/src/api/report/assignModerator.ts +0 -36
  46. package/src/api/report/createActivity.ts +0 -57
  47. package/src/api/report/createReport.ts +0 -93
  48. package/src/api/report/getAssignments.ts +0 -20
  49. package/src/api/report/getHistoricalStats.ts +0 -41
  50. package/src/api/report/getLatestReport.ts +0 -44
  51. package/src/api/report/getLiveStats.ts +0 -26
  52. package/src/api/report/getReport.ts +0 -55
  53. package/src/api/report/listActivities.ts +0 -37
  54. package/src/api/report/queryActivities.ts +0 -64
  55. package/src/api/report/queryReports.ts +0 -44
  56. package/src/api/report/reassignQueue.ts +0 -68
  57. package/src/api/report/refreshStats.ts +0 -27
  58. package/src/api/report/unassignModerator.ts +0 -21
  59. package/src/api/safelink/addRule.ts +0 -48
  60. package/src/api/safelink/queryEvents.ts +0 -32
  61. package/src/api/safelink/queryRules.ts +0 -58
  62. package/src/api/safelink/removeRule.ts +0 -42
  63. package/src/api/safelink/updateRule.ts +0 -48
  64. package/src/api/server/getConfig.ts +0 -35
  65. package/src/api/set/addValues.ts +0 -28
  66. package/src/api/set/deleteSet.ts +0 -34
  67. package/src/api/set/deleteValues.ts +0 -31
  68. package/src/api/set/getValues.ts +0 -42
  69. package/src/api/set/querySets.ts +0 -36
  70. package/src/api/set/upsertSet.ts +0 -38
  71. package/src/api/setting/listOptions.ts +0 -44
  72. package/src/api/setting/removeOptions.ts +0 -64
  73. package/src/api/setting/upsertOption.ts +0 -156
  74. package/src/api/team/addMember.ts +0 -51
  75. package/src/api/team/deleteMember.ts +0 -29
  76. package/src/api/team/listMembers.ts +0 -20
  77. package/src/api/team/updateMember.ts +0 -47
  78. package/src/api/util.ts +0 -265
  79. package/src/api/verification/grantVerifications.ts +0 -90
  80. package/src/api/verification/listVerifications.ts +0 -44
  81. package/src/api/verification/revokeVerifications.ts +0 -43
  82. package/src/api/well-known.ts +0 -46
  83. package/src/assignment/index.ts +0 -728
  84. package/src/auth-verifier.ts +0 -227
  85. package/src/background.ts +0 -183
  86. package/src/communication-service/template.ts +0 -110
  87. package/src/communication-service/util.ts +0 -8
  88. package/src/config/config.ts +0 -211
  89. package/src/config/env.ts +0 -95
  90. package/src/config/index.ts +0 -3
  91. package/src/config/secrets.ts +0 -17
  92. package/src/context.ts +0 -399
  93. package/src/daemon/blob-diverter.ts +0 -186
  94. package/src/daemon/context.ts +0 -247
  95. package/src/daemon/event-pusher.ts +0 -363
  96. package/src/daemon/event-reverser.ts +0 -128
  97. package/src/daemon/index.ts +0 -33
  98. package/src/daemon/job-cursor.ts +0 -33
  99. package/src/daemon/materialized-view-refresher.ts +0 -33
  100. package/src/daemon/queue-router.ts +0 -101
  101. package/src/daemon/scheduled-action-processor.ts +0 -304
  102. package/src/daemon/stats-computer.ts +0 -101
  103. package/src/daemon/strike-expiry-processor.ts +0 -95
  104. package/src/daemon/team-profile-synchronizer.ts +0 -15
  105. package/src/daemon/verification-listener.ts +0 -169
  106. package/src/db/index.ts +0 -203
  107. package/src/db/migrations/20231219T205730722Z-init.ts +0 -170
  108. package/src/db/migrations/20240116T085607200Z-communication-template.ts +0 -23
  109. package/src/db/migrations/20240201T051104136Z-mod-event-blobs.ts +0 -15
  110. package/src/db/migrations/20240208T213404429Z-add-tags-column-to-moderation-subject.ts +0 -31
  111. package/src/db/migrations/20240228T003647759Z-add-label-sigs.ts +0 -25
  112. package/src/db/migrations/20240408T192432676Z-mute-reporting.ts +0 -15
  113. package/src/db/migrations/20240506T225055595Z-message-subject.ts +0 -21
  114. package/src/db/migrations/20240521T211332580Z-member.ts +0 -17
  115. package/src/db/migrations/20240814T003647759Z-event-created-at-index.ts +0 -13
  116. package/src/db/migrations/20240903T205730722Z-add-template-lang.ts +0 -12
  117. package/src/db/migrations/20240904T205730722Z-add-subject-did-index.ts +0 -13
  118. package/src/db/migrations/20241001T205730722Z-subject-status-review-state-index.ts +0 -15
  119. package/src/db/migrations/20241008T205730722Z-sets.ts +0 -53
  120. package/src/db/migrations/20241018T205730722Z-setting.ts +0 -27
  121. package/src/db/migrations/20241026T205730722Z-add-hosting-status-to-subject-status.ts +0 -57
  122. package/src/db/migrations/20241220T144630860Z-stats-materialized-views.ts +0 -215
  123. package/src/db/migrations/20250204T003647759Z-add-subject-priority-score.ts +0 -22
  124. package/src/db/migrations/20250211T003647759Z-add-reporter-stats-index.ts +0 -38
  125. package/src/db/migrations/20250211T132135150Z-moderation-event-message-partial-idx.ts +0 -26
  126. package/src/db/migrations/20250221T132135150Z-member-details.ts +0 -14
  127. package/src/db/migrations/20250404T201720309Z-subject-status-sort-idxs.ts +0 -18
  128. package/src/db/migrations/20250415T201720309Z-verification.ts +0 -34
  129. package/src/db/migrations/20250417T201720309Z-firehose-cursor.ts +0 -16
  130. package/src/db/migrations/20250609T110704000Z-safelink.ts +0 -53
  131. package/src/db/migrations/20250618T180246000Z-add-mod-tool-to-moderation-event.ts +0 -18
  132. package/src/db/migrations/20250701T000000000Z-add-age-assurance-state.ts +0 -25
  133. package/src/db/migrations/20250715T000000000Z-add-mod-event-external-id.ts +0 -15
  134. package/src/db/migrations/20250718T150931000Z-update-appeal-reason-stats.ts +0 -310
  135. package/src/db/migrations/20250813T000000000Z-mod-tool-batch-id-index.ts +0 -14
  136. package/src/db/migrations/20250923T000000000Z-scheduled-actions.ts +0 -56
  137. package/src/db/migrations/20251008T120000000Z-add-strike-system.ts +0 -87
  138. package/src/db/migrations/20260210T154806448Z-mod-event-created-by-indexes.ts +0 -22
  139. package/src/db/migrations/20260219T164523000Z-create-report-table.ts +0 -155
  140. package/src/db/migrations/20260219T165302248Z-moderator-assignment.ts +0 -42
  141. package/src/db/migrations/20260225T000000000Z-add-report-queue-table.ts +0 -41
  142. package/src/db/migrations/20260313T000000000Z-add-report-activity-table.ts +0 -48
  143. package/src/db/migrations/20260318T152058935Z-add-report-stat.ts +0 -35
  144. package/src/db/migrations/20260428T000000000Z-add-expiring-tag-table.ts +0 -32
  145. package/src/db/migrations/20260513T202941104Z-add-subject-convo-id.ts +0 -114
  146. package/src/db/migrations/20260602T120000000Z-add-report-activity-created-index.ts +0 -17
  147. package/src/db/migrations/index.ts +0 -44
  148. package/src/db/migrations/provider.ts +0 -26
  149. package/src/db/pagination.ts +0 -335
  150. package/src/db/schema/account_events_stats.ts +0 -16
  151. package/src/db/schema/account_record_events_stats.ts +0 -15
  152. package/src/db/schema/account_record_status_stats.ts +0 -15
  153. package/src/db/schema/account_strike.ts +0 -13
  154. package/src/db/schema/blob_push_event.ts +0 -21
  155. package/src/db/schema/communication_template.ts +0 -19
  156. package/src/db/schema/expiring_tag.ts +0 -18
  157. package/src/db/schema/firehose_cursor.ts +0 -13
  158. package/src/db/schema/index.ts +0 -60
  159. package/src/db/schema/job_cursor.ts +0 -13
  160. package/src/db/schema/label.ts +0 -22
  161. package/src/db/schema/member.ts +0 -22
  162. package/src/db/schema/moderation_event.ts +0 -61
  163. package/src/db/schema/moderation_subject_status.ts +0 -52
  164. package/src/db/schema/moderator_assignment.ts +0 -16
  165. package/src/db/schema/ozone_set.ts +0 -24
  166. package/src/db/schema/record_events_stats.ts +0 -15
  167. package/src/db/schema/record_push_event.ts +0 -21
  168. package/src/db/schema/repo_push_event.ts +0 -19
  169. package/src/db/schema/report.ts +0 -28
  170. package/src/db/schema/report_activity.ts +0 -22
  171. package/src/db/schema/report_queue.ts +0 -21
  172. package/src/db/schema/report_stat.ts +0 -27
  173. package/src/db/schema/safelink.ts +0 -39
  174. package/src/db/schema/scheduled-action.ts +0 -25
  175. package/src/db/schema/setting.ts +0 -24
  176. package/src/db/schema/signing_key.ts +0 -10
  177. package/src/db/schema/verification.ts +0 -21
  178. package/src/db/types.ts +0 -24
  179. package/src/error.ts +0 -12
  180. package/src/image-invalidator.ts +0 -7
  181. package/src/index.ts +0 -154
  182. package/src/jetstream/service.ts +0 -107
  183. package/src/logger.ts +0 -29
  184. package/src/mod-service/expiring-tags.ts +0 -104
  185. package/src/mod-service/index.ts +0 -1842
  186. package/src/mod-service/profile.ts +0 -139
  187. package/src/mod-service/report.ts +0 -429
  188. package/src/mod-service/status.ts +0 -549
  189. package/src/mod-service/strike.ts +0 -96
  190. package/src/mod-service/subject.ts +0 -311
  191. package/src/mod-service/types.ts +0 -96
  192. package/src/mod-service/util.ts +0 -99
  193. package/src/mod-service/views.ts +0 -912
  194. package/src/queue/service.ts +0 -603
  195. package/src/report/activity.ts +0 -281
  196. package/src/report/handle-report-update.ts +0 -209
  197. package/src/report/reassign.ts +0 -109
  198. package/src/report/stats.ts +0 -852
  199. package/src/report/views.ts +0 -239
  200. package/src/safelink/service.ts +0 -304
  201. package/src/scheduled-action/service.ts +0 -281
  202. package/src/scheduled-action/types.ts +0 -17
  203. package/src/sequencer/index.ts +0 -2
  204. package/src/sequencer/outbox.ts +0 -123
  205. package/src/sequencer/sequencer.ts +0 -147
  206. package/src/set/service.ts +0 -230
  207. package/src/setting/constants.ts +0 -3
  208. package/src/setting/service.ts +0 -148
  209. package/src/setting/types.ts +0 -3
  210. package/src/setting/validators.ts +0 -333
  211. package/src/tag-service/content-tagger.ts +0 -30
  212. package/src/tag-service/embed-tagger.ts +0 -70
  213. package/src/tag-service/index.ts +0 -70
  214. package/src/tag-service/language-data.ts +0 -561
  215. package/src/tag-service/language-tagger.ts +0 -101
  216. package/src/tag-service/util.ts +0 -13
  217. package/src/team/index.ts +0 -296
  218. package/src/util.ts +0 -230
  219. package/src/verification/issuer.ts +0 -146
  220. package/src/verification/service.ts +0 -208
  221. package/src/verification/util.ts +0 -53
  222. package/test.env +0 -2
  223. package/tests/3p-labeler.test.ts +0 -288
  224. package/tests/__snapshots__/account-strikes.test.ts.snap +0 -159
  225. package/tests/__snapshots__/age-assurance.test.ts.snap +0 -66
  226. package/tests/__snapshots__/blob-divert.test.ts.snap +0 -219
  227. package/tests/__snapshots__/get-account-timeline.test.ts.snap +0 -36
  228. package/tests/__snapshots__/get-record.test.ts.snap +0 -271
  229. package/tests/__snapshots__/get-records.test.ts.snap +0 -175
  230. package/tests/__snapshots__/get-repo.test.ts.snap +0 -91
  231. package/tests/__snapshots__/get-repos.test.ts.snap +0 -127
  232. package/tests/__snapshots__/get-starter-pack.test.ts.snap +0 -535
  233. package/tests/__snapshots__/get-subjects.test.ts.snap +0 -529
  234. package/tests/__snapshots__/moderation-events.test.ts.snap +0 -347
  235. package/tests/__snapshots__/moderation-statuses.test.ts.snap +0 -276
  236. package/tests/__snapshots__/moderation.test.ts.snap +0 -85
  237. package/tests/__snapshots__/report-reason.test.ts.snap +0 -14
  238. package/tests/__snapshots__/safelink.test.ts.snap +0 -179
  239. package/tests/__snapshots__/scheduled-action.test.ts.snap +0 -61
  240. package/tests/__snapshots__/sets.test.ts.snap +0 -46
  241. package/tests/__snapshots__/settings.test.ts.snap +0 -52
  242. package/tests/__snapshots__/team.test.ts.snap +0 -374
  243. package/tests/__snapshots__/verification-listener.test.ts.snap +0 -152
  244. package/tests/__snapshots__/verification.test.ts.snap +0 -302
  245. package/tests/_util.ts +0 -242
  246. package/tests/account-strikes.test.ts +0 -184
  247. package/tests/ack-all-subjects-of-account.test.ts +0 -177
  248. package/tests/age-assurance.test.ts +0 -372
  249. package/tests/blob-divert.test.ts +0 -106
  250. package/tests/communication-templates.test.ts +0 -149
  251. package/tests/content-tagger.test.ts +0 -170
  252. package/tests/db.test.ts +0 -184
  253. package/tests/expiring-label.test.ts +0 -72
  254. package/tests/expiring-tags.test.ts +0 -232
  255. package/tests/get-account-timeline.test.ts +0 -85
  256. package/tests/get-config.test.ts +0 -55
  257. package/tests/get-lists.test.ts +0 -111
  258. package/tests/get-profiles.test.ts +0 -70
  259. package/tests/get-record.test.ts +0 -130
  260. package/tests/get-records.test.ts +0 -91
  261. package/tests/get-repo.test.ts +0 -171
  262. package/tests/get-report.test.ts +0 -136
  263. package/tests/get-reporter-stats.test.ts +0 -132
  264. package/tests/get-repos.test.ts +0 -91
  265. package/tests/get-starter-pack.test.ts +0 -115
  266. package/tests/get-subjects.test.ts +0 -81
  267. package/tests/mod-tool.test.ts +0 -268
  268. package/tests/moderation-appeals.test.ts +0 -260
  269. package/tests/moderation-events.test.ts +0 -756
  270. package/tests/moderation-status-tags.test.ts +0 -140
  271. package/tests/moderation-statuses.test.ts +0 -495
  272. package/tests/moderation.test.ts +0 -992
  273. package/tests/protected-tags.test.ts +0 -218
  274. package/tests/query-labels.test.ts +0 -238
  275. package/tests/query-reports.test.ts +0 -608
  276. package/tests/queue-assignment.test.ts +0 -428
  277. package/tests/queue-router.test.ts +0 -306
  278. package/tests/queues.test.ts +0 -690
  279. package/tests/record-and-account-events.test.ts +0 -197
  280. package/tests/repo-search.test.ts +0 -136
  281. package/tests/report-action.test.ts +0 -308
  282. package/tests/report-activity.test.ts +0 -711
  283. package/tests/report-assignment.test.ts +0 -517
  284. package/tests/report-muting.test.ts +0 -100
  285. package/tests/report-reason.test.ts +0 -154
  286. package/tests/report-reassign-queue.test.ts +0 -340
  287. package/tests/report-routing.test.ts +0 -245
  288. package/tests/report-stats.test.ts +0 -545
  289. package/tests/revoke-account-credentials.test.ts +0 -54
  290. package/tests/safelink.test.ts +0 -534
  291. package/tests/scheduled-action-processor.test.ts +0 -488
  292. package/tests/scheduled-action.test.ts +0 -334
  293. package/tests/sequencer.test.ts +0 -227
  294. package/tests/server.test.ts +0 -62
  295. package/tests/sets.test.ts +0 -246
  296. package/tests/settings.test.ts +0 -308
  297. package/tests/strike-expiry-processor.test.ts +0 -299
  298. package/tests/subject-priority-score.test.ts +0 -96
  299. package/tests/takedown.test.ts +0 -105
  300. package/tests/team.test.ts +0 -216
  301. package/tests/verification-listener.test.ts +0 -129
  302. package/tests/verification.test.ts +0 -186
  303. package/tsconfig.build.json +0 -9
  304. package/tsconfig.build.tsbuildinfo +0 -1
  305. package/tsconfig.json +0 -7
  306. package/tsconfig.tests.json +0 -8
@@ -1,139 +0,0 @@
1
- import AtpAgent, { AppBskyLabelerDefs } from '@atproto/api'
2
- import { InvalidRequestError } from '@atproto/xrpc-server'
3
- import { OzoneConfig } from '../config/index.js'
4
- import {
5
- REASONAPPEAL,
6
- REASONMISLEADING,
7
- REASONOTHER,
8
- REASONRUDE,
9
- REASONSEXUAL,
10
- REASONSPAM,
11
- REASONVIOLATION,
12
- } from '../lexicon/types/com/atproto/moderation/defs.js'
13
- import { httpLogger } from '../logger.js'
14
-
15
- // Reverse mapping from new ozone namespaced reason types to old com.atproto namespaced reason types
16
- export const NEW_TO_OLD_REASON_MAPPING: Record<string, string> = {
17
- 'tools.ozone.report.defs#reasonAppeal': REASONAPPEAL,
18
- 'tools.ozone.report.defs#reasonOther': REASONOTHER,
19
-
20
- 'tools.ozone.report.defs#reasonViolenceAnimal': REASONVIOLATION,
21
- 'tools.ozone.report.defs#reasonViolenceThreats': REASONVIOLATION,
22
- 'tools.ozone.report.defs#reasonViolenceGraphicContent': REASONVIOLATION,
23
- 'tools.ozone.report.defs#reasonViolenceGlorification': REASONVIOLATION,
24
- 'tools.ozone.report.defs#reasonViolenceExtremistContent': REASONVIOLATION,
25
- 'tools.ozone.report.defs#reasonViolenceTrafficking': REASONVIOLATION,
26
- 'tools.ozone.report.defs#reasonViolenceOther': REASONVIOLATION,
27
-
28
- 'tools.ozone.report.defs#reasonSexualAbuseContent': REASONSEXUAL,
29
- 'tools.ozone.report.defs#reasonSexualNCII': REASONSEXUAL,
30
- 'tools.ozone.report.defs#reasonSexualDeepfake': REASONSEXUAL,
31
- 'tools.ozone.report.defs#reasonSexualAnimal': REASONSEXUAL,
32
- 'tools.ozone.report.defs#reasonSexualUnlabeled': REASONSEXUAL,
33
- 'tools.ozone.report.defs#reasonSexualOther': REASONSEXUAL,
34
-
35
- 'tools.ozone.report.defs#reasonChildSafetyCSAM': REASONVIOLATION,
36
- 'tools.ozone.report.defs#reasonChildSafetyGroom': REASONVIOLATION,
37
- 'tools.ozone.report.defs#reasonChildSafetyPrivacy': REASONVIOLATION,
38
- 'tools.ozone.report.defs#reasonChildSafetyHarassment': REASONVIOLATION,
39
- 'tools.ozone.report.defs#reasonChildSafetyOther': REASONVIOLATION,
40
-
41
- 'tools.ozone.report.defs#reasonHarassmentTroll': REASONRUDE,
42
- 'tools.ozone.report.defs#reasonHarassmentTargeted': REASONRUDE,
43
- 'tools.ozone.report.defs#reasonHarassmentHateSpeech': REASONRUDE,
44
- 'tools.ozone.report.defs#reasonHarassmentDoxxing': REASONRUDE,
45
- 'tools.ozone.report.defs#reasonHarassmentOther': REASONRUDE,
46
-
47
- 'tools.ozone.report.defs#reasonMisleadingBot': REASONMISLEADING,
48
- 'tools.ozone.report.defs#reasonMisleadingImpersonation': REASONMISLEADING,
49
- 'tools.ozone.report.defs#reasonMisleadingSpam': REASONSPAM,
50
- 'tools.ozone.report.defs#reasonMisleadingScam': REASONMISLEADING,
51
- 'tools.ozone.report.defs#reasonMisleadingElections': REASONMISLEADING,
52
- 'tools.ozone.report.defs#reasonMisleadingOther': REASONMISLEADING,
53
-
54
- 'tools.ozone.report.defs#reasonRuleSiteSecurity': REASONVIOLATION,
55
- 'tools.ozone.report.defs#reasonRuleProhibitedSales': REASONVIOLATION,
56
- 'tools.ozone.report.defs#reasonRuleBanEvasion': REASONVIOLATION,
57
- 'tools.ozone.report.defs#reasonRuleOther': REASONVIOLATION,
58
-
59
- 'tools.ozone.report.defs#reasonSelfHarmContent': REASONVIOLATION,
60
- 'tools.ozone.report.defs#reasonSelfHarmED': REASONVIOLATION,
61
- 'tools.ozone.report.defs#reasonSelfHarmStunts': REASONVIOLATION,
62
- 'tools.ozone.report.defs#reasonSelfHarmSubstances': REASONVIOLATION,
63
- 'tools.ozone.report.defs#reasonSelfHarmOther': REASONVIOLATION,
64
- }
65
-
66
- interface CacheEntry {
67
- profile: AppBskyLabelerDefs.LabelerViewDetailed | null
68
- timestamp: number
69
- }
70
-
71
- export type ModerationServiceProfileCreator = () => ModerationServiceProfile
72
-
73
- export class ModerationServiceProfile {
74
- private cache: CacheEntry | null = null
75
- private CACHE_TTL: number
76
-
77
- constructor(
78
- private cfg: OzoneConfig,
79
- private appviewAgent: AtpAgent,
80
- cacheTTL?: number,
81
- ) {
82
- this.CACHE_TTL = cacheTTL || cfg.service.serviceRecordCacheTTL
83
- }
84
-
85
- static creator(
86
- cfg: OzoneConfig,
87
- appviewAgent: AtpAgent,
88
- ): ModerationServiceProfileCreator {
89
- return () => new ModerationServiceProfile(cfg, appviewAgent)
90
- }
91
-
92
- async getProfile() {
93
- const now = Date.now()
94
-
95
- if (!this.cache || now - this.cache.timestamp > this.CACHE_TTL) {
96
- try {
97
- const { data } = await this.appviewAgent.app.bsky.labeler.getServices({
98
- dids: [this.cfg.service.did],
99
- detailed: true,
100
- })
101
-
102
- if (AppBskyLabelerDefs.isLabelerViewDetailed(data.views?.[0])) {
103
- this.cache = {
104
- profile: data.views[0],
105
- timestamp: now,
106
- }
107
- }
108
- } catch (e) {
109
- // On error, fail open
110
- httpLogger.error(`Failed to fetch labeler profile: ${e?.['message']}`)
111
- }
112
- }
113
-
114
- return this.cache?.profile || null
115
- }
116
-
117
- async validateReasonType(reasonType: string): Promise<string> {
118
- const profile = await this.getProfile()
119
-
120
- if (!Array.isArray(profile?.reasonTypes)) {
121
- return reasonType
122
- }
123
-
124
- const supportedReasonTypes = profile.reasonTypes
125
-
126
- // Check if the reason type is directly supported
127
- if (supportedReasonTypes.includes(reasonType)) {
128
- return reasonType
129
- }
130
-
131
- // Allow new reason types only if they map to a supported old reason type
132
- const mappedOldReason = NEW_TO_OLD_REASON_MAPPING[reasonType]
133
- if (mappedOldReason && supportedReasonTypes.includes(mappedOldReason)) {
134
- return reasonType
135
- }
136
-
137
- throw new InvalidRequestError(`Invalid reason type: ${reasonType}`)
138
- }
139
- }
@@ -1,429 +0,0 @@
1
- import { sql } from 'kysely'
2
- import { AtUri } from '@atproto/syntax'
3
- import { Database } from '../db/index.js'
4
- import { Report } from '../db/schema/report.js'
5
- import { QueryParams } from '../lexicon/types/tools/ozone/report/queryReports.js'
6
- import {
7
- AlreadyInTargetState,
8
- InvalidStateTransition,
9
- handleReportUpdate,
10
- } from '../report/handle-report-update.js'
11
-
12
- export type ReportWithEvent = Omit<Report, 'id'> & {
13
- id: number
14
- subjectDid: string
15
- subjectUri: string | null
16
- subjectCid: string | null
17
- reportedBy: string
18
- comment: string | null
19
- meta: Record<string, string | boolean | number> | null
20
- }
21
-
22
- export type QueryReportsResult = {
23
- reports: ReportWithEvent[]
24
- cursor: string | undefined
25
- }
26
- function reportQuery(db: Database) {
27
- return db.db
28
- .selectFrom('report as r')
29
- .innerJoin('moderation_event as me', 'me.id', 'r.eventId')
30
- .where('me.action', '=', 'tools.ozone.moderation.defs#modEventReport')
31
- }
32
-
33
- export async function queryReports(
34
- db: Database,
35
- params: QueryParams,
36
- ): Promise<QueryReportsResult> {
37
- let builder = reportQuery(db)
38
-
39
- if (params.queueId !== undefined) {
40
- builder = builder.where('r.queueId', '=', params.queueId)
41
- }
42
-
43
- builder = builder.where('r.status', '=', params.status)
44
-
45
- if (params.subject) {
46
- const isRecord = params.subject.startsWith('at://')
47
- if (isRecord) {
48
- const uri = new AtUri(params.subject)
49
- builder = builder
50
- .where('r.did', '=', uri.host)
51
- .where('r.recordPath', '=', `${uri.collection}/${uri.rkey}`)
52
- } else {
53
- builder = builder
54
- .where('r.did', '=', params.subject)
55
- .where('r.recordPath', '=', '')
56
- }
57
- }
58
-
59
- if (params.did) {
60
- builder = builder.where('r.did', '=', params.did)
61
- }
62
-
63
- if (params.subjectType) {
64
- const normalizedType = params.subjectType as 'account' | 'record'
65
- if (normalizedType === 'account') {
66
- builder = builder.where('r.recordPath', '=', '')
67
- } else if (normalizedType === 'record') {
68
- builder = builder.where('r.recordPath', '!=', '')
69
- }
70
- }
71
-
72
- if (params.collections?.length) {
73
- // Filter by collection prefix on recordPath (uses text_pattern_ops index)
74
- const collectionConditions = params.collections.map(
75
- (collection) => sql`r."recordPath" LIKE ${`${collection}/%`}`,
76
- )
77
- builder = builder.where(
78
- sql<boolean>`(${sql.join(collectionConditions, sql` OR `)})`,
79
- )
80
- }
81
-
82
- if (params.reportTypes?.length) {
83
- builder = builder.where('r.reportType', 'in', params.reportTypes)
84
- }
85
-
86
- if (params.isMuted !== undefined) {
87
- builder = builder.where('r.isMuted', '=', params.isMuted)
88
- }
89
-
90
- if (params.reportedAfter) {
91
- builder = builder.where('r.createdAt', '>', params.reportedAfter)
92
- }
93
-
94
- if (params.reportedBefore) {
95
- builder = builder.where('r.createdAt', '<', params.reportedBefore)
96
- }
97
-
98
- if (params.assignedTo) {
99
- builder = builder.where('r.assignedTo', '=', params.assignedTo)
100
- }
101
-
102
- const sortField = params.sortField ?? 'createdAt'
103
- const sortDirection = params.sortDirection ?? 'desc'
104
-
105
- builder = builder
106
- .orderBy(
107
- sortField === 'updatedAt' ? 'r.updatedAt' : 'r.createdAt',
108
- sortDirection,
109
- )
110
- .orderBy('r.id', 'desc')
111
-
112
- const limit = params.limit ?? 50
113
- if (params.cursor) {
114
- const [sortValue, id] = params.cursor.split('::')
115
- const sortCol = sortField === 'updatedAt' ? 'r.updatedAt' : 'r.createdAt'
116
- if (sortDirection === 'desc') {
117
- builder = builder.where(sql<boolean>`(
118
- ${sql.ref(sortCol)} < ${sortValue}
119
- OR (${sql.ref(sortCol)} = ${sortValue} AND r.id < ${Number(id)})
120
- )`)
121
- } else {
122
- builder = builder.where(sql<boolean>`(
123
- ${sql.ref(sortCol)} > ${sortValue}
124
- OR (${sql.ref(sortCol)} = ${sortValue} AND r.id > ${Number(id)})
125
- )`)
126
- }
127
- }
128
-
129
- const finalQuery = builder
130
- .selectAll('r')
131
- .select([
132
- 'me.subjectDid',
133
- 'me.subjectUri',
134
- 'me.subjectCid',
135
- 'me.createdBy as reportedBy',
136
- 'me.comment',
137
- 'me.meta',
138
- ])
139
- .limit(limit + 1)
140
-
141
- const reports = await finalQuery.execute()
142
-
143
- let cursor: string | undefined
144
- const hasMore = reports.length > limit
145
- if (hasMore) {
146
- const last = reports[limit - 1]
147
- const sortValue =
148
- sortField === 'updatedAt' ? last.updatedAt : last.createdAt
149
- cursor = `${sortValue}::${last.id}`
150
- }
151
-
152
- const reportsToReturn = hasMore ? reports.slice(0, limit) : reports
153
-
154
- return {
155
- reports: reportsToReturn,
156
- cursor,
157
- }
158
- }
159
-
160
- export async function getReportById(
161
- db: Database,
162
- id: number,
163
- ): Promise<ReportWithEvent | undefined> {
164
- return reportQuery(db)
165
- .where('r.id', '=', id)
166
- .selectAll('r')
167
- .select([
168
- 'me.subjectDid',
169
- 'me.subjectUri',
170
- 'me.subjectCid',
171
- 'me.createdBy as reportedBy',
172
- 'me.comment',
173
- 'me.meta',
174
- ])
175
- .executeTakeFirst()
176
- }
177
-
178
- export async function getReportsByIds(
179
- db: Database,
180
- ids: number[],
181
- ): Promise<ReportWithEvent[]> {
182
- if (!ids.length) return []
183
- return reportQuery(db)
184
- .where('r.id', 'in', ids)
185
- .selectAll('r')
186
- .select([
187
- 'me.subjectDid',
188
- 'me.subjectUri',
189
- 'me.subjectCid',
190
- 'me.createdBy as reportedBy',
191
- 'me.comment',
192
- 'me.meta',
193
- ])
194
- .execute()
195
- }
196
-
197
- export async function getLatestReport(
198
- db: Database,
199
- ): Promise<ReportWithEvent | undefined> {
200
- return reportQuery(db)
201
- .selectAll('r')
202
- .select([
203
- 'me.subjectDid',
204
- 'me.subjectUri',
205
- 'me.subjectCid',
206
- 'me.createdBy as reportedBy',
207
- 'me.comment',
208
- 'me.meta',
209
- ])
210
- .orderBy('r.id', 'desc')
211
- .limit(1)
212
- .executeTakeFirst()
213
- }
214
-
215
- export type FindReportsForSubjectParams = {
216
- subjectDid: string
217
- subjectUri?: string | null
218
- reportIds?: number[]
219
- reportTypes?: string[]
220
- targetAll?: boolean
221
- }
222
-
223
- export type ReportResult = {
224
- id: number
225
- eventId: number
226
- queueId: number | null
227
- queuedAt: string | null
228
- actionEventIds: number[] | null
229
- actionNote: string | null
230
- isMuted: boolean
231
- status: string
232
- createdAt: string
233
- updatedAt: string
234
- }
235
-
236
- export async function findReportsForSubject(
237
- db: Database,
238
- params: FindReportsForSubjectParams,
239
- ): Promise<ReportResult[]> {
240
- let builder = reportQuery(db).where('r.did', '=', params.subjectDid)
241
-
242
- // Filter by subject URI (if provided, match exactly; if null/undefined, match repo-level)
243
- if (params.subjectUri) {
244
- const uri = new AtUri(params.subjectUri)
245
- builder = builder.where(
246
- 'r.recordPath',
247
- '=',
248
- `${uri.collection}/${uri.rkey}`,
249
- )
250
- } else {
251
- builder = builder.where('r.recordPath', '=', '')
252
- }
253
-
254
- if (params.targetAll) {
255
- // Target all open/escalated reports on the subject
256
- builder = builder.where('r.status', 'not in', ['closed'])
257
- } else if (params.reportIds?.length) {
258
- // Target specific report IDs — still enforce state transition rules
259
- builder = builder
260
- .where('r.id', 'in', params.reportIds)
261
- .where('r.status', 'not in', ['closed'])
262
- } else if (params.reportTypes?.length) {
263
- // Target reports matching specific report types
264
- builder = builder
265
- .where('r.reportType', 'in', params.reportTypes)
266
- .where('r.status', 'not in', ['closed'])
267
- } else {
268
- // No targeting criteria provided
269
- return []
270
- }
271
-
272
- const reports = await builder.selectAll('r').execute()
273
-
274
- return reports
275
- }
276
-
277
- export type ProcessReportActionParams = {
278
- db: Database
279
- reportAction: {
280
- ids?: number[]
281
- types?: string[]
282
- all?: boolean
283
- note?: string
284
- }
285
- subjectDid: string
286
- subjectUri: string | null
287
- eventId: number
288
- eventType: string
289
- createdBy: string
290
- }
291
-
292
- /**
293
- * Validates and processes a report action by:
294
- * 1. Finding matching reports based on targeting criteria
295
- * 2. Validating that specified report IDs exist and belong to the subject
296
- * 3. Bulk-updating reports with the action event ID, note, and status
297
- * 4. Bulk-inserting a report_activity row for each updated report
298
- *
299
- * @throws InvalidRequestError if validation fails
300
- */
301
- export async function processReportAction(
302
- params: ProcessReportActionParams,
303
- ): Promise<number> {
304
- const {
305
- db,
306
- reportAction,
307
- subjectDid,
308
- subjectUri,
309
- eventId,
310
- eventType,
311
- createdBy,
312
- } = params
313
-
314
- // Find reports matching the criteria
315
- const matchingReports = await findReportsForSubject(db, {
316
- subjectDid,
317
- subjectUri,
318
- reportIds: reportAction.ids,
319
- reportTypes: reportAction.types,
320
- targetAll: reportAction.all,
321
- })
322
-
323
- // Validate that reports were found for ids and types
324
- if (matchingReports.length === 0) {
325
- if (reportAction.ids?.length) {
326
- throw new Error(
327
- 'No matching reports found for the specified report IDs on this subject',
328
- )
329
- } else if (reportAction.types?.length) {
330
- throw new Error(
331
- 'No matching reports found for the specified report types on this subject',
332
- )
333
- }
334
- // For 'all', it's okay if no reports exist
335
- return 0
336
- }
337
-
338
- // Validate that all specified report IDs were found
339
- if (reportAction.ids?.length) {
340
- const foundIds = new Set(matchingReports.map((r) => r.id))
341
- const requestedIds = new Set(reportAction.ids)
342
- const missingIds = [...requestedIds].filter((id) => !foundIds.has(id))
343
-
344
- if (missingIds.length > 0) {
345
- throw new Error(
346
- `Report IDs ${missingIds.join(', ')} do not exist, are already closed, or do not belong to this subject`,
347
- )
348
- }
349
- }
350
-
351
- // Determine per-report transitions via the pure state machine.
352
- // Skip reports whose current status doesn't allow the transition.
353
- const validUpdates: {
354
- id: number
355
- nextStatus: string
356
- activityType: string
357
- previousStatus: string
358
- }[] = []
359
-
360
- for (const report of matchingReports) {
361
- try {
362
- const result = handleReportUpdate(report.status, {
363
- type: 'event',
364
- eventType,
365
- })
366
- if (result.nextStatus && result.activity) {
367
- validUpdates.push({
368
- id: report.id,
369
- nextStatus: result.nextStatus,
370
- activityType: result.activity.activityType,
371
- previousStatus: result.activity.previousStatus,
372
- })
373
- }
374
- } catch (err) {
375
- if (
376
- err instanceof AlreadyInTargetState ||
377
- err instanceof InvalidStateTransition
378
- ) {
379
- // Skip reports that can't transition — silent per design
380
- continue
381
- }
382
- throw err
383
- }
384
- }
385
-
386
- if (!validUpdates.length) {
387
- return 0
388
- }
389
-
390
- const now = new Date().toISOString()
391
- const updateIds = validUpdates.map((u) => u.id)
392
-
393
- // Bulk UPDATE reports that passed validation
394
- // All valid reports share the same target status since they come from the
395
- // same event type, so a single UPDATE is sufficient.
396
- const status = validUpdates[0].nextStatus
397
- const closedAt = status === 'closed' ? now : null
398
- await db.db
399
- .updateTable('report')
400
- .set({
401
- actionEventIds: sql`COALESCE("actionEventIds", '[]'::jsonb) || ${JSON.stringify(eventId)}::jsonb`,
402
- actionNote: reportAction.note ?? null,
403
- status,
404
- updatedAt: now,
405
- closedAt,
406
- })
407
- .where('id', 'in', updateIds)
408
- .execute()
409
-
410
- // Bulk INSERT one activity per updated report
411
- await db.db
412
- .insertInto('report_activity')
413
- .values(
414
- validUpdates.map((u) => ({
415
- reportId: u.id,
416
- activityType: u.activityType,
417
- previousStatus: u.previousStatus,
418
- internalNote: null,
419
- publicNote: reportAction.note ?? null,
420
- meta: null,
421
- isAutomated: false,
422
- createdBy,
423
- createdAt: now,
424
- })),
425
- )
426
- .execute()
427
-
428
- return validUpdates.length
429
- }