@atproto/ozone 0.1.172 → 0.1.174

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 (450) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/api/index.d.ts.map +1 -1
  3. package/dist/api/index.js +40 -0
  4. package/dist/api/index.js.map +1 -1
  5. package/dist/api/moderation/emitEvent.d.ts.map +1 -1
  6. package/dist/api/moderation/emitEvent.js +31 -0
  7. package/dist/api/moderation/emitEvent.js.map +1 -1
  8. package/dist/api/queue/assignModerator.d.ts +4 -0
  9. package/dist/api/queue/assignModerator.d.ts.map +1 -0
  10. package/dist/api/queue/assignModerator.js +28 -0
  11. package/dist/api/queue/assignModerator.js.map +1 -0
  12. package/dist/api/queue/createQueue.d.ts +4 -0
  13. package/dist/api/queue/createQueue.d.ts.map +1 -0
  14. package/dist/api/queue/createQueue.js +44 -0
  15. package/dist/api/queue/createQueue.js.map +1 -0
  16. package/dist/api/queue/deleteQueue.d.ts +4 -0
  17. package/dist/api/queue/deleteQueue.d.ts.map +1 -0
  18. package/dist/api/queue/deleteQueue.js +40 -0
  19. package/dist/api/queue/deleteQueue.js.map +1 -0
  20. package/dist/api/queue/getAssignments.d.ts +4 -0
  21. package/dist/api/queue/getAssignments.d.ts.map +1 -0
  22. package/dist/api/queue/getAssignments.js +19 -0
  23. package/dist/api/queue/getAssignments.js.map +1 -0
  24. package/dist/api/queue/listQueues.d.ts +4 -0
  25. package/dist/api/queue/listQueues.d.ts.map +1 -0
  26. package/dist/api/queue/listQueues.js +29 -0
  27. package/dist/api/queue/listQueues.js.map +1 -0
  28. package/dist/api/queue/routeReports.d.ts +4 -0
  29. package/dist/api/queue/routeReports.d.ts.map +1 -0
  30. package/dist/api/queue/routeReports.js +33 -0
  31. package/dist/api/queue/routeReports.js.map +1 -0
  32. package/dist/api/queue/unassignModerator.d.ts +4 -0
  33. package/dist/api/queue/unassignModerator.d.ts.map +1 -0
  34. package/dist/api/queue/unassignModerator.js +24 -0
  35. package/dist/api/queue/unassignModerator.js.map +1 -0
  36. package/dist/api/queue/updateQueue.d.ts +4 -0
  37. package/dist/api/queue/updateQueue.d.ts.map +1 -0
  38. package/dist/api/queue/updateQueue.js +39 -0
  39. package/dist/api/queue/updateQueue.js.map +1 -0
  40. package/dist/api/report/assignModerator.d.ts +4 -0
  41. package/dist/api/report/assignModerator.d.ts.map +1 -0
  42. package/dist/api/report/assignModerator.js +33 -0
  43. package/dist/api/report/assignModerator.js.map +1 -0
  44. package/dist/api/report/createActivity.d.ts +4 -0
  45. package/dist/api/report/createActivity.d.ts.map +1 -0
  46. package/dist/api/report/createActivity.js +44 -0
  47. package/dist/api/report/createActivity.js.map +1 -0
  48. package/dist/api/report/getAssignments.d.ts +4 -0
  49. package/dist/api/report/getAssignments.d.ts.map +1 -0
  50. package/dist/api/report/getAssignments.js +19 -0
  51. package/dist/api/report/getAssignments.js.map +1 -0
  52. package/dist/api/report/getHistoricalStats.d.ts +4 -0
  53. package/dist/api/report/getHistoricalStats.d.ts.map +1 -0
  54. package/dist/api/report/getHistoricalStats.js +32 -0
  55. package/dist/api/report/getHistoricalStats.js.map +1 -0
  56. package/dist/api/report/getLatestReport.d.ts +4 -0
  57. package/dist/api/report/getLatestReport.d.ts.map +1 -0
  58. package/dist/api/report/getLatestReport.js +31 -0
  59. package/dist/api/report/getLatestReport.js.map +1 -0
  60. package/dist/api/report/getLiveStats.d.ts +4 -0
  61. package/dist/api/report/getLiveStats.d.ts.map +1 -0
  62. package/dist/api/report/getLiveStats.js +25 -0
  63. package/dist/api/report/getLiveStats.js.map +1 -0
  64. package/dist/api/report/getReport.d.ts +4 -0
  65. package/dist/api/report/getReport.d.ts.map +1 -0
  66. package/dist/api/report/getReport.js +35 -0
  67. package/dist/api/report/getReport.js.map +1 -0
  68. package/dist/api/report/listActivities.d.ts +4 -0
  69. package/dist/api/report/listActivities.d.ts.map +1 -0
  70. package/dist/api/report/listActivities.js +25 -0
  71. package/dist/api/report/listActivities.js.map +1 -0
  72. package/dist/api/report/queryReports.d.ts +4 -0
  73. package/dist/api/report/queryReports.d.ts.map +1 -0
  74. package/dist/api/report/queryReports.js +29 -0
  75. package/dist/api/report/queryReports.js.map +1 -0
  76. package/dist/api/report/reassignQueue.d.ts +4 -0
  77. package/dist/api/report/reassignQueue.d.ts.map +1 -0
  78. package/dist/api/report/reassignQueue.js +45 -0
  79. package/dist/api/report/reassignQueue.js.map +1 -0
  80. package/dist/api/report/refreshStats.d.ts +4 -0
  81. package/dist/api/report/refreshStats.d.ts.map +1 -0
  82. package/dist/api/report/refreshStats.js +26 -0
  83. package/dist/api/report/refreshStats.js.map +1 -0
  84. package/dist/api/report/unassignModerator.d.ts +4 -0
  85. package/dist/api/report/unassignModerator.d.ts.map +1 -0
  86. package/dist/api/report/unassignModerator.js +21 -0
  87. package/dist/api/report/unassignModerator.js.map +1 -0
  88. package/dist/api/util.d.ts +2 -0
  89. package/dist/api/util.d.ts.map +1 -1
  90. package/dist/api/util.js +9 -1
  91. package/dist/api/util.js.map +1 -1
  92. package/dist/assignment/index.d.ts +89 -0
  93. package/dist/assignment/index.d.ts.map +1 -0
  94. package/dist/assignment/index.js +537 -0
  95. package/dist/assignment/index.js.map +1 -0
  96. package/dist/config/config.d.ts +14 -0
  97. package/dist/config/config.d.ts.map +1 -1
  98. package/dist/config/config.js +9 -0
  99. package/dist/config/config.js.map +1 -1
  100. package/dist/config/env.d.ts +3 -0
  101. package/dist/config/env.d.ts.map +1 -1
  102. package/dist/config/env.js +3 -0
  103. package/dist/config/env.js.map +1 -1
  104. package/dist/context.d.ts +9 -0
  105. package/dist/context.d.ts.map +1 -1
  106. package/dist/context.js +31 -10
  107. package/dist/context.js.map +1 -1
  108. package/dist/daemon/context.d.ts +6 -0
  109. package/dist/daemon/context.d.ts.map +1 -1
  110. package/dist/daemon/context.js +28 -4
  111. package/dist/daemon/context.js.map +1 -1
  112. package/dist/daemon/event-reverser.d.ts +1 -0
  113. package/dist/daemon/event-reverser.d.ts.map +1 -1
  114. package/dist/daemon/event-reverser.js +42 -1
  115. package/dist/daemon/event-reverser.js.map +1 -1
  116. package/dist/daemon/job-cursor.d.ts +5 -0
  117. package/dist/daemon/job-cursor.d.ts.map +1 -0
  118. package/dist/daemon/job-cursor.js +28 -0
  119. package/dist/daemon/job-cursor.js.map +1 -0
  120. package/dist/daemon/queue-router.d.ts +17 -0
  121. package/dist/daemon/queue-router.d.ts.map +1 -0
  122. package/dist/daemon/queue-router.js +114 -0
  123. package/dist/daemon/queue-router.js.map +1 -0
  124. package/dist/daemon/stats-computer.d.ts +51 -0
  125. package/dist/daemon/stats-computer.d.ts.map +1 -0
  126. package/dist/daemon/stats-computer.js +117 -0
  127. package/dist/daemon/stats-computer.js.map +1 -0
  128. package/dist/daemon/strike-expiry-processor.d.ts.map +1 -1
  129. package/dist/daemon/strike-expiry-processor.js +4 -19
  130. package/dist/daemon/strike-expiry-processor.js.map +1 -1
  131. package/dist/db/migrations/20260219T164523000Z-create-report-table.d.ts +4 -0
  132. package/dist/db/migrations/20260219T164523000Z-create-report-table.d.ts.map +1 -0
  133. package/dist/db/migrations/20260219T164523000Z-create-report-table.js +126 -0
  134. package/dist/db/migrations/20260219T164523000Z-create-report-table.js.map +1 -0
  135. package/dist/db/migrations/20260219T165302248Z-moderator-assignment.d.ts +4 -0
  136. package/dist/db/migrations/20260219T165302248Z-moderator-assignment.d.ts.map +1 -0
  137. package/dist/db/migrations/20260219T165302248Z-moderator-assignment.js +35 -0
  138. package/dist/db/migrations/20260219T165302248Z-moderator-assignment.js.map +1 -0
  139. package/dist/db/migrations/20260225T000000000Z-add-report-queue-table.d.ts +4 -0
  140. package/dist/db/migrations/20260225T000000000Z-add-report-queue-table.d.ts.map +1 -0
  141. package/dist/db/migrations/20260225T000000000Z-add-report-queue-table.js +36 -0
  142. package/dist/db/migrations/20260225T000000000Z-add-report-queue-table.js.map +1 -0
  143. package/dist/db/migrations/20260313T000000000Z-add-report-activity-table.d.ts +4 -0
  144. package/dist/db/migrations/20260313T000000000Z-add-report-activity-table.d.ts.map +1 -0
  145. package/dist/db/migrations/20260313T000000000Z-add-report-activity-table.js +39 -0
  146. package/dist/db/migrations/20260313T000000000Z-add-report-activity-table.js.map +1 -0
  147. package/dist/db/migrations/20260318T152058935Z-add-report-stat.d.ts +4 -0
  148. package/dist/db/migrations/20260318T152058935Z-add-report-stat.d.ts.map +1 -0
  149. package/dist/db/migrations/20260318T152058935Z-add-report-stat.js +34 -0
  150. package/dist/db/migrations/20260318T152058935Z-add-report-stat.js.map +1 -0
  151. package/dist/db/migrations/20260428T000000000Z-add-expiring-tag-table.d.ts +4 -0
  152. package/dist/db/migrations/20260428T000000000Z-add-expiring-tag-table.d.ts.map +1 -0
  153. package/dist/db/migrations/20260428T000000000Z-add-expiring-tag-table.js +32 -0
  154. package/dist/db/migrations/20260428T000000000Z-add-expiring-tag-table.js.map +1 -0
  155. package/dist/db/migrations/index.d.ts +6 -0
  156. package/dist/db/migrations/index.d.ts.map +1 -1
  157. package/dist/db/migrations/index.js +7 -1
  158. package/dist/db/migrations/index.js.map +1 -1
  159. package/dist/db/pagination.d.ts +31 -0
  160. package/dist/db/pagination.d.ts.map +1 -1
  161. package/dist/db/pagination.js +74 -1
  162. package/dist/db/pagination.js.map +1 -1
  163. package/dist/db/schema/expiring_tag.d.ts +15 -0
  164. package/dist/db/schema/expiring_tag.d.ts.map +1 -0
  165. package/dist/db/schema/expiring_tag.js +5 -0
  166. package/dist/db/schema/expiring_tag.js.map +1 -0
  167. package/dist/db/schema/index.d.ts +7 -1
  168. package/dist/db/schema/index.d.ts.map +1 -1
  169. package/dist/db/schema/index.js.map +1 -1
  170. package/dist/db/schema/moderator_assignment.d.ts +14 -0
  171. package/dist/db/schema/moderator_assignment.d.ts.map +1 -0
  172. package/dist/db/schema/moderator_assignment.js +5 -0
  173. package/dist/db/schema/moderator_assignment.js.map +1 -0
  174. package/dist/db/schema/report.d.ts +25 -0
  175. package/dist/db/schema/report.d.ts.map +1 -0
  176. package/dist/db/schema/report.js +5 -0
  177. package/dist/db/schema/report.js.map +1 -0
  178. package/dist/db/schema/report_activity.d.ts +18 -0
  179. package/dist/db/schema/report_activity.d.ts.map +1 -0
  180. package/dist/db/schema/report_activity.js +5 -0
  181. package/dist/db/schema/report_activity.js.map +1 -0
  182. package/dist/db/schema/report_queue.d.ts +19 -0
  183. package/dist/db/schema/report_queue.d.ts.map +1 -0
  184. package/dist/db/schema/report_queue.js +5 -0
  185. package/dist/db/schema/report_queue.js.map +1 -0
  186. package/dist/db/schema/report_stat.d.ts +20 -0
  187. package/dist/db/schema/report_stat.d.ts.map +1 -0
  188. package/dist/db/schema/report_stat.js +5 -0
  189. package/dist/db/schema/report_stat.js.map +1 -0
  190. package/dist/lexicon/index.d.ts +50 -0
  191. package/dist/lexicon/index.d.ts.map +1 -1
  192. package/dist/lexicon/index.js +120 -2
  193. package/dist/lexicon/index.js.map +1 -1
  194. package/dist/lexicon/lexicons.d.ts +11255 -7885
  195. package/dist/lexicon/lexicons.d.ts.map +1 -1
  196. package/dist/lexicon/lexicons.js +1900 -120
  197. package/dist/lexicon/lexicons.js.map +1 -1
  198. package/dist/lexicon/types/app/bsky/embed/external.d.ts +2 -0
  199. package/dist/lexicon/types/app/bsky/embed/external.d.ts.map +1 -1
  200. package/dist/lexicon/types/app/bsky/embed/external.js.map +1 -1
  201. package/dist/lexicon/types/chat/bsky/actor/defs.d.ts +8 -2
  202. package/dist/lexicon/types/chat/bsky/actor/defs.d.ts.map +1 -1
  203. package/dist/lexicon/types/chat/bsky/actor/defs.js +9 -0
  204. package/dist/lexicon/types/chat/bsky/actor/defs.js.map +1 -1
  205. package/dist/lexicon/types/chat/bsky/convo/defs.d.ts +37 -10
  206. package/dist/lexicon/types/chat/bsky/convo/defs.d.ts.map +1 -1
  207. package/dist/lexicon/types/chat/bsky/convo/defs.js +9 -0
  208. package/dist/lexicon/types/chat/bsky/convo/defs.js.map +1 -1
  209. package/dist/lexicon/types/chat/bsky/convo/getMessages.d.ts +3 -0
  210. package/dist/lexicon/types/chat/bsky/convo/getMessages.d.ts.map +1 -1
  211. package/dist/lexicon/types/chat/bsky/convo/getMessages.js.map +1 -1
  212. package/dist/lexicon/types/tools/ozone/moderation/defs.d.ts +2 -0
  213. package/dist/lexicon/types/tools/ozone/moderation/defs.d.ts.map +1 -1
  214. package/dist/lexicon/types/tools/ozone/moderation/defs.js.map +1 -1
  215. package/dist/lexicon/types/tools/ozone/moderation/emitEvent.d.ts +19 -0
  216. package/dist/lexicon/types/tools/ozone/moderation/emitEvent.d.ts.map +1 -1
  217. package/dist/lexicon/types/tools/ozone/moderation/emitEvent.js +9 -0
  218. package/dist/lexicon/types/tools/ozone/moderation/emitEvent.js.map +1 -1
  219. package/dist/lexicon/types/tools/ozone/queue/assignModerator.d.ts +27 -0
  220. package/dist/lexicon/types/tools/ozone/queue/assignModerator.d.ts.map +1 -0
  221. package/dist/lexicon/types/tools/ozone/queue/assignModerator.js +7 -0
  222. package/dist/lexicon/types/tools/ozone/queue/assignModerator.js.map +1 -0
  223. package/dist/lexicon/types/tools/ozone/queue/createQueue.d.ts +35 -0
  224. package/dist/lexicon/types/tools/ozone/queue/createQueue.d.ts.map +1 -0
  225. package/dist/lexicon/types/tools/ozone/queue/createQueue.js +7 -0
  226. package/dist/lexicon/types/tools/ozone/queue/createQueue.js.map +1 -0
  227. package/dist/lexicon/types/tools/ozone/queue/defs.d.ts +62 -0
  228. package/dist/lexicon/types/tools/ozone/queue/defs.d.ts.map +1 -0
  229. package/dist/lexicon/types/tools/ozone/queue/defs.js +34 -0
  230. package/dist/lexicon/types/tools/ozone/queue/defs.js.map +1 -0
  231. package/dist/lexicon/types/tools/ozone/queue/deleteQueue.d.ts +29 -0
  232. package/dist/lexicon/types/tools/ozone/queue/deleteQueue.d.ts.map +1 -0
  233. package/dist/lexicon/types/tools/ozone/queue/deleteQueue.js +7 -0
  234. package/dist/lexicon/types/tools/ozone/queue/deleteQueue.js.map +1 -0
  235. package/dist/lexicon/types/tools/ozone/queue/getAssignments.d.ts +30 -0
  236. package/dist/lexicon/types/tools/ozone/queue/getAssignments.d.ts.map +1 -0
  237. package/dist/lexicon/types/tools/ozone/queue/getAssignments.js +7 -0
  238. package/dist/lexicon/types/tools/ozone/queue/getAssignments.js.map +1 -0
  239. package/dist/lexicon/types/tools/ozone/queue/listQueues.d.ts +32 -0
  240. package/dist/lexicon/types/tools/ozone/queue/listQueues.d.ts.map +1 -0
  241. package/dist/lexicon/types/tools/ozone/queue/listQueues.js +7 -0
  242. package/dist/lexicon/types/tools/ozone/queue/listQueues.js.map +1 -0
  243. package/dist/lexicon/types/tools/ozone/queue/routeReports.d.ts +31 -0
  244. package/dist/lexicon/types/tools/ozone/queue/routeReports.d.ts.map +1 -0
  245. package/dist/lexicon/types/tools/ozone/queue/routeReports.js +7 -0
  246. package/dist/lexicon/types/tools/ozone/queue/routeReports.js.map +1 -0
  247. package/dist/lexicon/types/tools/ozone/queue/unassignModerator.d.ts +18 -0
  248. package/dist/lexicon/types/tools/ozone/queue/unassignModerator.d.ts.map +1 -0
  249. package/dist/lexicon/types/tools/ozone/queue/unassignModerator.js +7 -0
  250. package/dist/lexicon/types/tools/ozone/queue/unassignModerator.js.map +1 -0
  251. package/dist/lexicon/types/tools/ozone/queue/updateQueue.d.ts +32 -0
  252. package/dist/lexicon/types/tools/ozone/queue/updateQueue.d.ts.map +1 -0
  253. package/dist/lexicon/types/tools/ozone/queue/updateQueue.js +7 -0
  254. package/dist/lexicon/types/tools/ozone/queue/updateQueue.js.map +1 -0
  255. package/dist/lexicon/types/tools/ozone/report/assignModerator.d.ts +31 -0
  256. package/dist/lexicon/types/tools/ozone/report/assignModerator.d.ts.map +1 -0
  257. package/dist/lexicon/types/tools/ozone/report/assignModerator.js +7 -0
  258. package/dist/lexicon/types/tools/ozone/report/assignModerator.js.map +1 -0
  259. package/dist/lexicon/types/tools/ozone/report/createActivity.d.ts +37 -0
  260. package/dist/lexicon/types/tools/ozone/report/createActivity.d.ts.map +1 -0
  261. package/dist/lexicon/types/tools/ozone/report/createActivity.js +7 -0
  262. package/dist/lexicon/types/tools/ozone/report/createActivity.js.map +1 -0
  263. package/dist/lexicon/types/tools/ozone/report/defs.d.ts +185 -0
  264. package/dist/lexicon/types/tools/ozone/report/defs.d.ts.map +1 -1
  265. package/dist/lexicon/types/tools/ozone/report/defs.js +108 -0
  266. package/dist/lexicon/types/tools/ozone/report/defs.js.map +1 -1
  267. package/dist/lexicon/types/tools/ozone/report/getAssignments.d.ts +30 -0
  268. package/dist/lexicon/types/tools/ozone/report/getAssignments.d.ts.map +1 -0
  269. package/dist/lexicon/types/tools/ozone/report/getAssignments.js +7 -0
  270. package/dist/lexicon/types/tools/ozone/report/getAssignments.js.map +1 -0
  271. package/dist/lexicon/types/tools/ozone/report/getHistoricalStats.d.ts +36 -0
  272. package/dist/lexicon/types/tools/ozone/report/getHistoricalStats.d.ts.map +1 -0
  273. package/dist/lexicon/types/tools/ozone/report/getHistoricalStats.js +7 -0
  274. package/dist/lexicon/types/tools/ozone/report/getHistoricalStats.js.map +1 -0
  275. package/dist/lexicon/types/tools/ozone/report/getLatestReport.d.ts +21 -0
  276. package/dist/lexicon/types/tools/ozone/report/getLatestReport.d.ts.map +1 -0
  277. package/dist/lexicon/types/tools/ozone/report/getLatestReport.js +7 -0
  278. package/dist/lexicon/types/tools/ozone/report/getLatestReport.js.map +1 -0
  279. package/dist/lexicon/types/tools/ozone/report/getLiveStats.d.ts +27 -0
  280. package/dist/lexicon/types/tools/ozone/report/getLiveStats.d.ts.map +1 -0
  281. package/dist/lexicon/types/tools/ozone/report/getLiveStats.js +7 -0
  282. package/dist/lexicon/types/tools/ozone/report/getLiveStats.js.map +1 -0
  283. package/dist/lexicon/types/tools/ozone/report/getReport.d.ts +22 -0
  284. package/dist/lexicon/types/tools/ozone/report/getReport.d.ts.map +1 -0
  285. package/dist/lexicon/types/tools/ozone/report/getReport.js +7 -0
  286. package/dist/lexicon/types/tools/ozone/report/getReport.js.map +1 -0
  287. package/dist/lexicon/types/tools/ozone/report/listActivities.d.ts +26 -0
  288. package/dist/lexicon/types/tools/ozone/report/listActivities.d.ts.map +1 -0
  289. package/dist/lexicon/types/tools/ozone/report/listActivities.js +7 -0
  290. package/dist/lexicon/types/tools/ozone/report/listActivities.js.map +1 -0
  291. package/dist/lexicon/types/tools/ozone/report/queryReports.d.ts +48 -0
  292. package/dist/lexicon/types/tools/ozone/report/queryReports.d.ts.map +1 -0
  293. package/dist/lexicon/types/tools/ozone/report/queryReports.js +7 -0
  294. package/dist/lexicon/types/tools/ozone/report/queryReports.js.map +1 -0
  295. package/dist/lexicon/types/tools/ozone/report/reassignQueue.d.ts +31 -0
  296. package/dist/lexicon/types/tools/ozone/report/reassignQueue.d.ts.map +1 -0
  297. package/dist/lexicon/types/tools/ozone/report/reassignQueue.js +7 -0
  298. package/dist/lexicon/types/tools/ozone/report/reassignQueue.js.map +1 -0
  299. package/dist/lexicon/types/tools/ozone/report/refreshStats.d.ts +28 -0
  300. package/dist/lexicon/types/tools/ozone/report/refreshStats.d.ts.map +1 -0
  301. package/dist/lexicon/types/tools/ozone/report/refreshStats.js +7 -0
  302. package/dist/lexicon/types/tools/ozone/report/refreshStats.js.map +1 -0
  303. package/dist/lexicon/types/tools/ozone/report/unassignModerator.d.ts +25 -0
  304. package/dist/lexicon/types/tools/ozone/report/unassignModerator.d.ts.map +1 -0
  305. package/dist/lexicon/types/tools/ozone/report/unassignModerator.js +7 -0
  306. package/dist/lexicon/types/tools/ozone/report/unassignModerator.js.map +1 -0
  307. package/dist/mod-service/expiring-tags.d.ts +27 -0
  308. package/dist/mod-service/expiring-tags.d.ts.map +1 -0
  309. package/dist/mod-service/expiring-tags.js +62 -0
  310. package/dist/mod-service/expiring-tags.js.map +1 -0
  311. package/dist/mod-service/index.d.ts +3 -1
  312. package/dist/mod-service/index.d.ts.map +1 -1
  313. package/dist/mod-service/index.js +61 -2
  314. package/dist/mod-service/index.js.map +1 -1
  315. package/dist/mod-service/report.d.ts +64 -0
  316. package/dist/mod-service/report.d.ts.map +1 -0
  317. package/dist/mod-service/report.js +282 -0
  318. package/dist/mod-service/report.js.map +1 -0
  319. package/dist/mod-service/status.d.ts +24 -0
  320. package/dist/mod-service/status.d.ts.map +1 -1
  321. package/dist/queue/service.d.ts +86 -0
  322. package/dist/queue/service.d.ts.map +1 -0
  323. package/dist/queue/service.js +430 -0
  324. package/dist/queue/service.js.map +1 -0
  325. package/dist/report/activity.d.ts +77 -0
  326. package/dist/report/activity.d.ts.map +1 -0
  327. package/dist/report/activity.js +141 -0
  328. package/dist/report/activity.js.map +1 -0
  329. package/dist/report/handle-report-update.d.ts +47 -0
  330. package/dist/report/handle-report-update.d.ts.map +1 -0
  331. package/dist/report/handle-report-update.js +178 -0
  332. package/dist/report/handle-report-update.js.map +1 -0
  333. package/dist/report/reassign.d.ts +10 -0
  334. package/dist/report/reassign.d.ts.map +1 -0
  335. package/dist/report/reassign.js +75 -0
  336. package/dist/report/reassign.js.map +1 -0
  337. package/dist/report/stats.d.ts +105 -0
  338. package/dist/report/stats.d.ts.map +1 -0
  339. package/dist/report/stats.js +619 -0
  340. package/dist/report/stats.js.map +1 -0
  341. package/dist/report/views.d.ts +111 -0
  342. package/dist/report/views.d.ts.map +1 -0
  343. package/dist/report/views.js +156 -0
  344. package/dist/report/views.js.map +1 -0
  345. package/dist/team/index.d.ts +1 -0
  346. package/dist/team/index.d.ts.map +1 -1
  347. package/dist/team/index.js +11 -0
  348. package/dist/team/index.js.map +1 -1
  349. package/package.json +3 -3
  350. package/src/api/index.ts +40 -0
  351. package/src/api/moderation/emitEvent.ts +38 -0
  352. package/src/api/queue/assignModerator.ts +31 -0
  353. package/src/api/queue/createQueue.ts +62 -0
  354. package/src/api/queue/deleteQueue.ts +56 -0
  355. package/src/api/queue/getAssignments.ts +19 -0
  356. package/src/api/queue/listQueues.ts +39 -0
  357. package/src/api/queue/routeReports.ts +44 -0
  358. package/src/api/queue/unassignModerator.ts +26 -0
  359. package/src/api/queue/updateQueue.ts +54 -0
  360. package/src/api/report/assignModerator.ts +36 -0
  361. package/src/api/report/createActivity.ts +57 -0
  362. package/src/api/report/getAssignments.ts +20 -0
  363. package/src/api/report/getHistoricalStats.ts +41 -0
  364. package/src/api/report/getLatestReport.ts +44 -0
  365. package/src/api/report/getLiveStats.ts +26 -0
  366. package/src/api/report/getReport.ts +55 -0
  367. package/src/api/report/listActivities.ts +34 -0
  368. package/src/api/report/queryReports.ts +44 -0
  369. package/src/api/report/reassignQueue.ts +68 -0
  370. package/src/api/report/refreshStats.ts +27 -0
  371. package/src/api/report/unassignModerator.ts +21 -0
  372. package/src/api/util.ts +12 -0
  373. package/src/assignment/index.ts +731 -0
  374. package/src/config/config.ts +27 -0
  375. package/src/config/env.ts +8 -0
  376. package/src/context.ts +31 -0
  377. package/src/daemon/context.ts +34 -0
  378. package/src/daemon/event-reverser.ts +50 -1
  379. package/src/daemon/job-cursor.ts +33 -0
  380. package/src/daemon/queue-router.ts +101 -0
  381. package/src/daemon/stats-computer.ts +101 -0
  382. package/src/daemon/strike-expiry-processor.ts +4 -20
  383. package/src/db/migrations/20260219T164523000Z-create-report-table.ts +155 -0
  384. package/src/db/migrations/20260219T165302248Z-moderator-assignment.ts +42 -0
  385. package/src/db/migrations/20260225T000000000Z-add-report-queue-table.ts +41 -0
  386. package/src/db/migrations/20260313T000000000Z-add-report-activity-table.ts +48 -0
  387. package/src/db/migrations/20260318T152058935Z-add-report-stat.ts +35 -0
  388. package/src/db/migrations/20260428T000000000Z-add-expiring-tag-table.ts +32 -0
  389. package/src/db/migrations/index.ts +6 -0
  390. package/src/db/pagination.ts +85 -0
  391. package/src/db/schema/expiring_tag.ts +17 -0
  392. package/src/db/schema/index.ts +13 -1
  393. package/src/db/schema/moderator_assignment.ts +16 -0
  394. package/src/db/schema/report.ts +27 -0
  395. package/src/db/schema/report_activity.ts +22 -0
  396. package/src/db/schema/report_queue.ts +21 -0
  397. package/src/db/schema/report_stat.ts +27 -0
  398. package/src/lexicon/index.ts +280 -0
  399. package/src/lexicon/lexicons.ts +2083 -214
  400. package/src/lexicon/types/app/bsky/embed/external.ts +2 -0
  401. package/src/lexicon/types/chat/bsky/actor/defs.ts +17 -1
  402. package/src/lexicon/types/chat/bsky/convo/defs.ts +50 -10
  403. package/src/lexicon/types/chat/bsky/convo/getMessages.ts +3 -0
  404. package/src/lexicon/types/tools/ozone/moderation/defs.ts +2 -0
  405. package/src/lexicon/types/tools/ozone/moderation/emitEvent.ts +24 -0
  406. package/src/lexicon/types/tools/ozone/queue/assignModerator.ts +46 -0
  407. package/src/lexicon/types/tools/ozone/queue/createQueue.ts +54 -0
  408. package/src/lexicon/types/tools/ozone/queue/defs.ts +99 -0
  409. package/src/lexicon/types/tools/ozone/queue/deleteQueue.ts +48 -0
  410. package/src/lexicon/types/tools/ozone/queue/getAssignments.ts +48 -0
  411. package/src/lexicon/types/tools/ozone/queue/listQueues.ts +50 -0
  412. package/src/lexicon/types/tools/ozone/queue/routeReports.ts +50 -0
  413. package/src/lexicon/types/tools/ozone/queue/unassignModerator.ts +37 -0
  414. package/src/lexicon/types/tools/ozone/queue/updateQueue.ts +51 -0
  415. package/src/lexicon/types/tools/ozone/report/assignModerator.ts +50 -0
  416. package/src/lexicon/types/tools/ozone/report/createActivity.ts +60 -0
  417. package/src/lexicon/types/tools/ozone/report/defs.ts +327 -0
  418. package/src/lexicon/types/tools/ozone/report/getAssignments.ts +48 -0
  419. package/src/lexicon/types/tools/ozone/report/getHistoricalStats.ts +54 -0
  420. package/src/lexicon/types/tools/ozone/report/getLatestReport.ts +39 -0
  421. package/src/lexicon/types/tools/ozone/report/getLiveStats.ts +45 -0
  422. package/src/lexicon/types/tools/ozone/report/getReport.ts +38 -0
  423. package/src/lexicon/types/tools/ozone/report/listActivities.ts +44 -0
  424. package/src/lexicon/types/tools/ozone/report/queryReports.ts +72 -0
  425. package/src/lexicon/types/tools/ozone/report/reassignQueue.ts +55 -0
  426. package/src/lexicon/types/tools/ozone/report/refreshStats.ts +46 -0
  427. package/src/lexicon/types/tools/ozone/report/unassignModerator.ts +44 -0
  428. package/src/mod-service/expiring-tags.ts +98 -0
  429. package/src/mod-service/index.ts +71 -3
  430. package/src/mod-service/report.ts +408 -0
  431. package/src/queue/service.ts +599 -0
  432. package/src/report/activity.ts +234 -0
  433. package/src/report/handle-report-update.ts +209 -0
  434. package/src/report/reassign.ts +109 -0
  435. package/src/report/stats.ts +850 -0
  436. package/src/report/views.ts +241 -0
  437. package/src/team/index.ts +11 -0
  438. package/tests/expiring-tags.test.ts +231 -0
  439. package/tests/get-report.test.ts +136 -0
  440. package/tests/query-reports.test.ts +608 -0
  441. package/tests/queue-assignment.test.ts +428 -0
  442. package/tests/queue-router.test.ts +306 -0
  443. package/tests/queues.test.ts +690 -0
  444. package/tests/report-action.test.ts +308 -0
  445. package/tests/report-activity.test.ts +567 -0
  446. package/tests/report-assignment.test.ts +517 -0
  447. package/tests/report-reassign-queue.test.ts +340 -0
  448. package/tests/report-routing.test.ts +245 -0
  449. package/tests/report-stats.test.ts +545 -0
  450. package/tsconfig.build.tsbuildinfo +1 -1
@@ -0,0 +1,282 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.queryReports = queryReports;
4
+ exports.getReportById = getReportById;
5
+ exports.getLatestReport = getLatestReport;
6
+ exports.findReportsForSubject = findReportsForSubject;
7
+ exports.processReportAction = processReportAction;
8
+ const kysely_1 = require("kysely");
9
+ const syntax_1 = require("@atproto/syntax");
10
+ const handle_report_update_1 = require("../report/handle-report-update");
11
+ function reportQuery(db) {
12
+ return db.db
13
+ .selectFrom('report as r')
14
+ .innerJoin('moderation_event as me', 'me.id', 'r.eventId')
15
+ .where('me.action', '=', 'tools.ozone.moderation.defs#modEventReport');
16
+ }
17
+ async function queryReports(db, params) {
18
+ let builder = reportQuery(db);
19
+ if (params.queueId !== undefined) {
20
+ builder = builder.where('r.queueId', '=', params.queueId);
21
+ }
22
+ builder = builder.where('r.status', '=', params.status);
23
+ if (params.subject) {
24
+ const isRecord = params.subject.startsWith('at://');
25
+ if (isRecord) {
26
+ const uri = new syntax_1.AtUri(params.subject);
27
+ builder = builder
28
+ .where('r.did', '=', uri.host)
29
+ .where('r.recordPath', '=', `${uri.collection}/${uri.rkey}`);
30
+ }
31
+ else {
32
+ builder = builder
33
+ .where('r.did', '=', params.subject)
34
+ .where('r.recordPath', '=', '');
35
+ }
36
+ }
37
+ if (params.did) {
38
+ builder = builder.where('r.did', '=', params.did);
39
+ }
40
+ if (params.subjectType) {
41
+ const normalizedType = params.subjectType;
42
+ if (normalizedType === 'account') {
43
+ builder = builder.where('r.recordPath', '=', '');
44
+ }
45
+ else if (normalizedType === 'record') {
46
+ builder = builder.where('r.recordPath', '!=', '');
47
+ }
48
+ }
49
+ if (params.collections?.length) {
50
+ // Filter by collection prefix on recordPath (uses text_pattern_ops index)
51
+ const collectionConditions = params.collections.map((collection) => (0, kysely_1.sql) `r."recordPath" LIKE ${`${collection}/%`}`);
52
+ builder = builder.where((0, kysely_1.sql) `(${kysely_1.sql.join(collectionConditions, (0, kysely_1.sql) ` OR `)})`);
53
+ }
54
+ if (params.reportTypes?.length) {
55
+ builder = builder.where('r.reportType', 'in', params.reportTypes);
56
+ }
57
+ if (params.isMuted !== undefined) {
58
+ builder = builder.where('r.isMuted', '=', params.isMuted);
59
+ }
60
+ if (params.reportedAfter) {
61
+ builder = builder.where('r.createdAt', '>', params.reportedAfter);
62
+ }
63
+ if (params.reportedBefore) {
64
+ builder = builder.where('r.createdAt', '<', params.reportedBefore);
65
+ }
66
+ if (params.assignedTo) {
67
+ builder = builder.where('r.assignedTo', '=', params.assignedTo);
68
+ }
69
+ const sortField = params.sortField ?? 'createdAt';
70
+ const sortDirection = params.sortDirection ?? 'desc';
71
+ builder = builder
72
+ .orderBy(sortField === 'updatedAt' ? 'r.updatedAt' : 'r.createdAt', sortDirection)
73
+ .orderBy('r.id', 'desc');
74
+ const limit = params.limit ?? 50;
75
+ if (params.cursor) {
76
+ const [sortValue, id] = params.cursor.split('::');
77
+ const sortCol = sortField === 'updatedAt' ? 'r.updatedAt' : 'r.createdAt';
78
+ if (sortDirection === 'desc') {
79
+ builder = builder.where((0, kysely_1.sql) `(
80
+ ${kysely_1.sql.ref(sortCol)} < ${sortValue}
81
+ OR (${kysely_1.sql.ref(sortCol)} = ${sortValue} AND r.id < ${Number(id)})
82
+ )`);
83
+ }
84
+ else {
85
+ builder = builder.where((0, kysely_1.sql) `(
86
+ ${kysely_1.sql.ref(sortCol)} > ${sortValue}
87
+ OR (${kysely_1.sql.ref(sortCol)} = ${sortValue} AND r.id > ${Number(id)})
88
+ )`);
89
+ }
90
+ }
91
+ const finalQuery = builder
92
+ .selectAll('r')
93
+ .select([
94
+ 'me.subjectDid',
95
+ 'me.subjectUri',
96
+ 'me.subjectCid',
97
+ 'me.createdBy as reportedBy',
98
+ 'me.comment',
99
+ 'me.meta',
100
+ ])
101
+ .limit(limit + 1);
102
+ const reports = await finalQuery.execute();
103
+ let cursor;
104
+ const hasMore = reports.length > limit;
105
+ if (hasMore) {
106
+ const last = reports[limit - 1];
107
+ const sortValue = sortField === 'updatedAt' ? last.updatedAt : last.createdAt;
108
+ cursor = `${sortValue}::${last.id}`;
109
+ }
110
+ const reportsToReturn = hasMore ? reports.slice(0, limit) : reports;
111
+ return {
112
+ reports: reportsToReturn,
113
+ cursor,
114
+ };
115
+ }
116
+ async function getReportById(db, id) {
117
+ return reportQuery(db)
118
+ .where('r.id', '=', id)
119
+ .selectAll('r')
120
+ .select([
121
+ 'me.subjectDid',
122
+ 'me.subjectUri',
123
+ 'me.subjectCid',
124
+ 'me.createdBy as reportedBy',
125
+ 'me.comment',
126
+ 'me.meta',
127
+ ])
128
+ .executeTakeFirst();
129
+ }
130
+ async function getLatestReport(db) {
131
+ return reportQuery(db)
132
+ .selectAll('r')
133
+ .select([
134
+ 'me.subjectDid',
135
+ 'me.subjectUri',
136
+ 'me.subjectCid',
137
+ 'me.createdBy as reportedBy',
138
+ 'me.comment',
139
+ 'me.meta',
140
+ ])
141
+ .orderBy('r.id', 'desc')
142
+ .limit(1)
143
+ .executeTakeFirst();
144
+ }
145
+ async function findReportsForSubject(db, params) {
146
+ let builder = reportQuery(db).where('r.did', '=', params.subjectDid);
147
+ // Filter by subject URI (if provided, match exactly; if null/undefined, match repo-level)
148
+ if (params.subjectUri) {
149
+ const uri = new syntax_1.AtUri(params.subjectUri);
150
+ builder = builder.where('r.recordPath', '=', `${uri.collection}/${uri.rkey}`);
151
+ }
152
+ else {
153
+ builder = builder.where('r.recordPath', '=', '');
154
+ }
155
+ if (params.targetAll) {
156
+ // Target all open/escalated reports on the subject
157
+ builder = builder.where('r.status', 'not in', ['closed']);
158
+ }
159
+ else if (params.reportIds?.length) {
160
+ // Target specific report IDs — still enforce state transition rules
161
+ builder = builder
162
+ .where('r.id', 'in', params.reportIds)
163
+ .where('r.status', 'not in', ['closed']);
164
+ }
165
+ else if (params.reportTypes?.length) {
166
+ // Target reports matching specific report types
167
+ builder = builder
168
+ .where('r.reportType', 'in', params.reportTypes)
169
+ .where('r.status', 'not in', ['closed']);
170
+ }
171
+ else {
172
+ // No targeting criteria provided
173
+ return [];
174
+ }
175
+ const reports = await builder.selectAll('r').execute();
176
+ return reports;
177
+ }
178
+ /**
179
+ * Validates and processes a report action by:
180
+ * 1. Finding matching reports based on targeting criteria
181
+ * 2. Validating that specified report IDs exist and belong to the subject
182
+ * 3. Bulk-updating reports with the action event ID, note, and status
183
+ * 4. Bulk-inserting a report_activity row for each updated report
184
+ *
185
+ * @throws InvalidRequestError if validation fails
186
+ */
187
+ async function processReportAction(params) {
188
+ const { db, reportAction, subjectDid, subjectUri, eventId, eventType, createdBy, } = params;
189
+ // Find reports matching the criteria
190
+ const matchingReports = await findReportsForSubject(db, {
191
+ subjectDid,
192
+ subjectUri,
193
+ reportIds: reportAction.ids,
194
+ reportTypes: reportAction.types,
195
+ targetAll: reportAction.all,
196
+ });
197
+ // Validate that reports were found for ids and types
198
+ if (matchingReports.length === 0) {
199
+ if (reportAction.ids?.length) {
200
+ throw new Error('No matching reports found for the specified report IDs on this subject');
201
+ }
202
+ else if (reportAction.types?.length) {
203
+ throw new Error('No matching reports found for the specified report types on this subject');
204
+ }
205
+ // For 'all', it's okay if no reports exist
206
+ return 0;
207
+ }
208
+ // Validate that all specified report IDs were found
209
+ if (reportAction.ids?.length) {
210
+ const foundIds = new Set(matchingReports.map((r) => r.id));
211
+ const requestedIds = new Set(reportAction.ids);
212
+ const missingIds = [...requestedIds].filter((id) => !foundIds.has(id));
213
+ if (missingIds.length > 0) {
214
+ throw new Error(`Report IDs ${missingIds.join(', ')} do not exist, are already closed, or do not belong to this subject`);
215
+ }
216
+ }
217
+ // Determine per-report transitions via the pure state machine.
218
+ // Skip reports whose current status doesn't allow the transition.
219
+ const validUpdates = [];
220
+ for (const report of matchingReports) {
221
+ try {
222
+ const result = (0, handle_report_update_1.handleReportUpdate)(report.status, {
223
+ type: 'event',
224
+ eventType,
225
+ });
226
+ if (result.nextStatus && result.activity) {
227
+ validUpdates.push({
228
+ id: report.id,
229
+ nextStatus: result.nextStatus,
230
+ activityType: result.activity.activityType,
231
+ previousStatus: result.activity.previousStatus,
232
+ });
233
+ }
234
+ }
235
+ catch (err) {
236
+ if (err instanceof handle_report_update_1.AlreadyInTargetState ||
237
+ err instanceof handle_report_update_1.InvalidStateTransition) {
238
+ // Skip reports that can't transition — silent per design
239
+ continue;
240
+ }
241
+ throw err;
242
+ }
243
+ }
244
+ if (!validUpdates.length) {
245
+ return 0;
246
+ }
247
+ const now = new Date().toISOString();
248
+ const updateIds = validUpdates.map((u) => u.id);
249
+ // Bulk UPDATE reports that passed validation
250
+ // All valid reports share the same target status since they come from the
251
+ // same event type, so a single UPDATE is sufficient.
252
+ const status = validUpdates[0].nextStatus;
253
+ const closedAt = status === 'closed' ? now : null;
254
+ await db.db
255
+ .updateTable('report')
256
+ .set({
257
+ actionEventIds: (0, kysely_1.sql) `COALESCE("actionEventIds", '[]'::jsonb) || ${JSON.stringify(eventId)}::jsonb`,
258
+ actionNote: reportAction.note ?? null,
259
+ status,
260
+ updatedAt: now,
261
+ closedAt,
262
+ })
263
+ .where('id', 'in', updateIds)
264
+ .execute();
265
+ // Bulk INSERT one activity per updated report
266
+ await db.db
267
+ .insertInto('report_activity')
268
+ .values(validUpdates.map((u) => ({
269
+ reportId: u.id,
270
+ activityType: u.activityType,
271
+ previousStatus: u.previousStatus,
272
+ internalNote: null,
273
+ publicNote: reportAction.note ?? null,
274
+ meta: null,
275
+ isAutomated: false,
276
+ createdBy,
277
+ createdAt: now,
278
+ })))
279
+ .execute();
280
+ return validUpdates.length;
281
+ }
282
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/mod-service/report.ts"],"names":[],"mappings":"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","sourcesContent":["import { sql } from 'kysely'\nimport { AtUri } from '@atproto/syntax'\nimport { Database } from '../db'\nimport { Report } from '../db/schema/report'\nimport { QueryParams } from '../lexicon/types/tools/ozone/report/queryReports'\nimport {\n AlreadyInTargetState,\n InvalidStateTransition,\n handleReportUpdate,\n} from '../report/handle-report-update'\n\nexport type ReportWithEvent = Omit<Report, 'id'> & {\n id: number\n subjectDid: string\n subjectUri: string | null\n subjectCid: string | null\n reportedBy: string\n comment: string | null\n meta: Record<string, string | boolean | number> | null\n}\n\nexport type QueryReportsResult = {\n reports: ReportWithEvent[]\n cursor: string | undefined\n}\nfunction reportQuery(db: Database) {\n return db.db\n .selectFrom('report as r')\n .innerJoin('moderation_event as me', 'me.id', 'r.eventId')\n .where('me.action', '=', 'tools.ozone.moderation.defs#modEventReport')\n}\n\nexport async function queryReports(\n db: Database,\n params: QueryParams,\n): Promise<QueryReportsResult> {\n let builder = reportQuery(db)\n\n if (params.queueId !== undefined) {\n builder = builder.where('r.queueId', '=', params.queueId)\n }\n\n builder = builder.where('r.status', '=', params.status)\n\n if (params.subject) {\n const isRecord = params.subject.startsWith('at://')\n if (isRecord) {\n const uri = new AtUri(params.subject)\n builder = builder\n .where('r.did', '=', uri.host)\n .where('r.recordPath', '=', `${uri.collection}/${uri.rkey}`)\n } else {\n builder = builder\n .where('r.did', '=', params.subject)\n .where('r.recordPath', '=', '')\n }\n }\n\n if (params.did) {\n builder = builder.where('r.did', '=', params.did)\n }\n\n if (params.subjectType) {\n const normalizedType = params.subjectType as 'account' | 'record'\n if (normalizedType === 'account') {\n builder = builder.where('r.recordPath', '=', '')\n } else if (normalizedType === 'record') {\n builder = builder.where('r.recordPath', '!=', '')\n }\n }\n\n if (params.collections?.length) {\n // Filter by collection prefix on recordPath (uses text_pattern_ops index)\n const collectionConditions = params.collections.map(\n (collection) => sql`r.\"recordPath\" LIKE ${`${collection}/%`}`,\n )\n builder = builder.where(sql`(${sql.join(collectionConditions, sql` OR `)})`)\n }\n\n if (params.reportTypes?.length) {\n builder = builder.where('r.reportType', 'in', params.reportTypes)\n }\n\n if (params.isMuted !== undefined) {\n builder = builder.where('r.isMuted', '=', params.isMuted)\n }\n\n if (params.reportedAfter) {\n builder = builder.where('r.createdAt', '>', params.reportedAfter)\n }\n\n if (params.reportedBefore) {\n builder = builder.where('r.createdAt', '<', params.reportedBefore)\n }\n\n if (params.assignedTo) {\n builder = builder.where('r.assignedTo', '=', params.assignedTo)\n }\n\n const sortField = params.sortField ?? 'createdAt'\n const sortDirection = params.sortDirection ?? 'desc'\n\n builder = builder\n .orderBy(\n sortField === 'updatedAt' ? 'r.updatedAt' : 'r.createdAt',\n sortDirection,\n )\n .orderBy('r.id', 'desc')\n\n const limit = params.limit ?? 50\n if (params.cursor) {\n const [sortValue, id] = params.cursor.split('::')\n const sortCol = sortField === 'updatedAt' ? 'r.updatedAt' : 'r.createdAt'\n if (sortDirection === 'desc') {\n builder = builder.where(sql`(\n ${sql.ref(sortCol)} < ${sortValue}\n OR (${sql.ref(sortCol)} = ${sortValue} AND r.id < ${Number(id)})\n )`)\n } else {\n builder = builder.where(sql`(\n ${sql.ref(sortCol)} > ${sortValue}\n OR (${sql.ref(sortCol)} = ${sortValue} AND r.id > ${Number(id)})\n )`)\n }\n }\n\n const finalQuery = builder\n .selectAll('r')\n .select([\n 'me.subjectDid',\n 'me.subjectUri',\n 'me.subjectCid',\n 'me.createdBy as reportedBy',\n 'me.comment',\n 'me.meta',\n ])\n .limit(limit + 1)\n\n const reports = await finalQuery.execute()\n\n let cursor: string | undefined\n const hasMore = reports.length > limit\n if (hasMore) {\n const last = reports[limit - 1]\n const sortValue =\n sortField === 'updatedAt' ? last.updatedAt : last.createdAt\n cursor = `${sortValue}::${last.id}`\n }\n\n const reportsToReturn = hasMore ? reports.slice(0, limit) : reports\n\n return {\n reports: reportsToReturn,\n cursor,\n }\n}\n\nexport async function getReportById(\n db: Database,\n id: number,\n): Promise<ReportWithEvent | undefined> {\n return reportQuery(db)\n .where('r.id', '=', id)\n .selectAll('r')\n .select([\n 'me.subjectDid',\n 'me.subjectUri',\n 'me.subjectCid',\n 'me.createdBy as reportedBy',\n 'me.comment',\n 'me.meta',\n ])\n .executeTakeFirst()\n}\n\nexport async function getLatestReport(\n db: Database,\n): Promise<ReportWithEvent | undefined> {\n return reportQuery(db)\n .selectAll('r')\n .select([\n 'me.subjectDid',\n 'me.subjectUri',\n 'me.subjectCid',\n 'me.createdBy as reportedBy',\n 'me.comment',\n 'me.meta',\n ])\n .orderBy('r.id', 'desc')\n .limit(1)\n .executeTakeFirst()\n}\n\nexport type FindReportsForSubjectParams = {\n subjectDid: string\n subjectUri?: string | null\n reportIds?: number[]\n reportTypes?: string[]\n targetAll?: boolean\n}\n\nexport type ReportResult = {\n id: number\n eventId: number\n queueId: number | null\n queuedAt: string | null\n actionEventIds: number[] | null\n actionNote: string | null\n isMuted: boolean\n status: string\n createdAt: string\n updatedAt: string\n}\n\nexport async function findReportsForSubject(\n db: Database,\n params: FindReportsForSubjectParams,\n): Promise<ReportResult[]> {\n let builder = reportQuery(db).where('r.did', '=', params.subjectDid)\n\n // Filter by subject URI (if provided, match exactly; if null/undefined, match repo-level)\n if (params.subjectUri) {\n const uri = new AtUri(params.subjectUri)\n builder = builder.where(\n 'r.recordPath',\n '=',\n `${uri.collection}/${uri.rkey}`,\n )\n } else {\n builder = builder.where('r.recordPath', '=', '')\n }\n\n if (params.targetAll) {\n // Target all open/escalated reports on the subject\n builder = builder.where('r.status', 'not in', ['closed'])\n } else if (params.reportIds?.length) {\n // Target specific report IDs — still enforce state transition rules\n builder = builder\n .where('r.id', 'in', params.reportIds)\n .where('r.status', 'not in', ['closed'])\n } else if (params.reportTypes?.length) {\n // Target reports matching specific report types\n builder = builder\n .where('r.reportType', 'in', params.reportTypes)\n .where('r.status', 'not in', ['closed'])\n } else {\n // No targeting criteria provided\n return []\n }\n\n const reports = await builder.selectAll('r').execute()\n\n return reports\n}\n\nexport type ProcessReportActionParams = {\n db: Database\n reportAction: {\n ids?: number[]\n types?: string[]\n all?: boolean\n note?: string\n }\n subjectDid: string\n subjectUri: string | null\n eventId: number\n eventType: string\n createdBy: string\n}\n\n/**\n * Validates and processes a report action by:\n * 1. Finding matching reports based on targeting criteria\n * 2. Validating that specified report IDs exist and belong to the subject\n * 3. Bulk-updating reports with the action event ID, note, and status\n * 4. Bulk-inserting a report_activity row for each updated report\n *\n * @throws InvalidRequestError if validation fails\n */\nexport async function processReportAction(\n params: ProcessReportActionParams,\n): Promise<number> {\n const {\n db,\n reportAction,\n subjectDid,\n subjectUri,\n eventId,\n eventType,\n createdBy,\n } = params\n\n // Find reports matching the criteria\n const matchingReports = await findReportsForSubject(db, {\n subjectDid,\n subjectUri,\n reportIds: reportAction.ids,\n reportTypes: reportAction.types,\n targetAll: reportAction.all,\n })\n\n // Validate that reports were found for ids and types\n if (matchingReports.length === 0) {\n if (reportAction.ids?.length) {\n throw new Error(\n 'No matching reports found for the specified report IDs on this subject',\n )\n } else if (reportAction.types?.length) {\n throw new Error(\n 'No matching reports found for the specified report types on this subject',\n )\n }\n // For 'all', it's okay if no reports exist\n return 0\n }\n\n // Validate that all specified report IDs were found\n if (reportAction.ids?.length) {\n const foundIds = new Set(matchingReports.map((r) => r.id))\n const requestedIds = new Set(reportAction.ids)\n const missingIds = [...requestedIds].filter((id) => !foundIds.has(id))\n\n if (missingIds.length > 0) {\n throw new Error(\n `Report IDs ${missingIds.join(', ')} do not exist, are already closed, or do not belong to this subject`,\n )\n }\n }\n\n // Determine per-report transitions via the pure state machine.\n // Skip reports whose current status doesn't allow the transition.\n const validUpdates: {\n id: number\n nextStatus: string\n activityType: string\n previousStatus: string\n }[] = []\n\n for (const report of matchingReports) {\n try {\n const result = handleReportUpdate(report.status, {\n type: 'event',\n eventType,\n })\n if (result.nextStatus && result.activity) {\n validUpdates.push({\n id: report.id,\n nextStatus: result.nextStatus,\n activityType: result.activity.activityType,\n previousStatus: result.activity.previousStatus,\n })\n }\n } catch (err) {\n if (\n err instanceof AlreadyInTargetState ||\n err instanceof InvalidStateTransition\n ) {\n // Skip reports that can't transition — silent per design\n continue\n }\n throw err\n }\n }\n\n if (!validUpdates.length) {\n return 0\n }\n\n const now = new Date().toISOString()\n const updateIds = validUpdates.map((u) => u.id)\n\n // Bulk UPDATE reports that passed validation\n // All valid reports share the same target status since they come from the\n // same event type, so a single UPDATE is sufficient.\n const status = validUpdates[0].nextStatus\n const closedAt = status === 'closed' ? now : null\n await db.db\n .updateTable('report')\n .set({\n actionEventIds: sql`COALESCE(\"actionEventIds\", '[]'::jsonb) || ${JSON.stringify(eventId)}::jsonb`,\n actionNote: reportAction.note ?? null,\n status,\n updatedAt: now,\n closedAt,\n })\n .where('id', 'in', updateIds)\n .execute()\n\n // Bulk INSERT one activity per updated report\n await db.db\n .insertInto('report_activity')\n .values(\n validUpdates.map((u) => ({\n reportId: u.id,\n activityType: u.activityType,\n previousStatus: u.previousStatus,\n internalNote: null,\n publicNote: reportAction.note ?? null,\n meta: null,\n isAutomated: false,\n createdBy,\n createdAt: now,\n })),\n )\n .execute()\n\n return validUpdates.length\n}\n"]}
@@ -15,6 +15,7 @@ export declare const moderationSubjectStatusQueryBuilder: (db: DatabaseSchema) =
15
15
  set_detail: import("../db/schema/ozone_set").SetDetail;
16
16
  set_value: import("../db/schema/ozone_set").SetValue;
17
17
  setting: import("../db/schema/setting").Setting;
18
+ report: import("../db/schema/report").Report;
18
19
  account_events_stats: import("kysely/dist/cjs/util/type-utils").Nullable<import("../db/schema/account_events_stats").AccountEventsStats>;
19
20
  account_record_events_stats: import("kysely/dist/cjs/util/type-utils").Nullable<{
20
21
  subjectDid: import("kysely").GeneratedAlways<string>;
@@ -31,9 +32,14 @@ export declare const moderationSubjectStatusQueryBuilder: (db: DatabaseSchema) =
31
32
  takendownCount: import("kysely").GeneratedAlways<number>;
32
33
  }>;
33
34
  account_strike: import("kysely/dist/cjs/util/type-utils").Nullable<import("../db/schema/account_strike").AccountStrike>;
35
+ expiring_tag: import("../db/schema/expiring_tag").ExpiringTag;
34
36
  firehose_cursor: import("../db/schema/firehose_cursor").FirehoseCursor;
35
37
  job_cursor: import("../db/schema/job_cursor").JobCursor;
38
+ moderator_assignment: import("../db/schema/moderator_assignment").ModeratorAssignment;
36
39
  record_events_stats: import("../db/schema/record_events_stats").RecordEventsStats;
40
+ report_activity: import("../db/schema/report_activity").ReportActivity;
41
+ report_queue: import("../db/schema/report_queue").ReportQueue;
42
+ report_stat: import("../db/schema/report_stat").ReportStat;
37
43
  verification: import("../db/schema/verification").Verification;
38
44
  safelink_rule: import("../db/schema/safelink").SafelinkRule;
39
45
  safelink_event: import("../db/schema/safelink").SafelinkEvent;
@@ -80,6 +86,7 @@ export declare const moderationSubjectStatusQueryBuilder: (db: DatabaseSchema) =
80
86
  set_detail: import("../db/schema/ozone_set").SetDetail;
81
87
  set_value: import("../db/schema/ozone_set").SetValue;
82
88
  setting: import("../db/schema/setting").Setting;
89
+ report: import("../db/schema/report").Report;
83
90
  account_events_stats: import("kysely/dist/cjs/util/type-utils").Nullable<import("../db/schema/account_events_stats").AccountEventsStats>;
84
91
  account_record_events_stats: {
85
92
  subjectDid: import("kysely").GeneratedAlways<string>;
@@ -96,9 +103,14 @@ export declare const moderationSubjectStatusQueryBuilder: (db: DatabaseSchema) =
96
103
  takendownCount: import("kysely").GeneratedAlways<number>;
97
104
  };
98
105
  account_strike: import("../db/schema/account_strike").AccountStrike;
106
+ expiring_tag: import("../db/schema/expiring_tag").ExpiringTag;
99
107
  firehose_cursor: import("../db/schema/firehose_cursor").FirehoseCursor;
100
108
  job_cursor: import("../db/schema/job_cursor").JobCursor;
109
+ moderator_assignment: import("../db/schema/moderator_assignment").ModeratorAssignment;
101
110
  record_events_stats: import("../db/schema/record_events_stats").RecordEventsStats;
111
+ report_activity: import("../db/schema/report_activity").ReportActivity;
112
+ report_queue: import("../db/schema/report_queue").ReportQueue;
113
+ report_stat: import("../db/schema/report_stat").ReportStat;
102
114
  verification: import("../db/schema/verification").Verification;
103
115
  safelink_rule: import("../db/schema/safelink").SafelinkRule;
104
116
  safelink_event: import("../db/schema/safelink").SafelinkEvent;
@@ -116,6 +128,7 @@ export declare const moderationSubjectStatusQueryBuilder: (db: DatabaseSchema) =
116
128
  set_detail: import("../db/schema/ozone_set").SetDetail;
117
129
  set_value: import("../db/schema/ozone_set").SetValue;
118
130
  setting: import("../db/schema/setting").Setting;
131
+ report: import("../db/schema/report").Report;
119
132
  account_events_stats: import("kysely/dist/cjs/util/type-utils").Nullable<import("../db/schema/account_events_stats").AccountEventsStats>;
120
133
  account_record_events_stats: import("kysely/dist/cjs/util/type-utils").Nullable<{
121
134
  subjectDid: import("kysely").GeneratedAlways<string>;
@@ -132,9 +145,14 @@ export declare const moderationSubjectStatusQueryBuilder: (db: DatabaseSchema) =
132
145
  takendownCount: import("kysely").GeneratedAlways<number>;
133
146
  };
134
147
  account_strike: import("../db/schema/account_strike").AccountStrike;
148
+ expiring_tag: import("../db/schema/expiring_tag").ExpiringTag;
135
149
  firehose_cursor: import("../db/schema/firehose_cursor").FirehoseCursor;
136
150
  job_cursor: import("../db/schema/job_cursor").JobCursor;
151
+ moderator_assignment: import("../db/schema/moderator_assignment").ModeratorAssignment;
137
152
  record_events_stats: import("../db/schema/record_events_stats").RecordEventsStats;
153
+ report_activity: import("../db/schema/report_activity").ReportActivity;
154
+ report_queue: import("../db/schema/report_queue").ReportQueue;
155
+ report_stat: import("../db/schema/report_stat").ReportStat;
138
156
  verification: import("../db/schema/verification").Verification;
139
157
  safelink_rule: import("../db/schema/safelink").SafelinkRule;
140
158
  safelink_event: import("../db/schema/safelink").SafelinkEvent;
@@ -152,6 +170,7 @@ export declare const moderationSubjectStatusQueryBuilder: (db: DatabaseSchema) =
152
170
  set_detail: import("../db/schema/ozone_set").SetDetail;
153
171
  set_value: import("../db/schema/ozone_set").SetValue;
154
172
  setting: import("../db/schema/setting").Setting;
173
+ report: import("../db/schema/report").Report;
155
174
  account_events_stats: import("kysely/dist/cjs/util/type-utils").Nullable<import("../db/schema/account_events_stats").AccountEventsStats>;
156
175
  account_record_events_stats: import("kysely/dist/cjs/util/type-utils").Nullable<{
157
176
  subjectDid: import("kysely").GeneratedAlways<string>;
@@ -168,9 +187,14 @@ export declare const moderationSubjectStatusQueryBuilder: (db: DatabaseSchema) =
168
187
  takendownCount: import("kysely").GeneratedAlways<number>;
169
188
  }>;
170
189
  account_strike: import("../db/schema/account_strike").AccountStrike;
190
+ expiring_tag: import("../db/schema/expiring_tag").ExpiringTag;
171
191
  firehose_cursor: import("../db/schema/firehose_cursor").FirehoseCursor;
172
192
  job_cursor: import("../db/schema/job_cursor").JobCursor;
193
+ moderator_assignment: import("../db/schema/moderator_assignment").ModeratorAssignment;
173
194
  record_events_stats: import("../db/schema/record_events_stats").RecordEventsStats;
195
+ report_activity: import("../db/schema/report_activity").ReportActivity;
196
+ report_queue: import("../db/schema/report_queue").ReportQueue;
197
+ report_stat: import("../db/schema/report_stat").ReportStat;
174
198
  verification: import("../db/schema/verification").Verification;
175
199
  safelink_rule: import("../db/schema/safelink").SafelinkRule;
176
200
  safelink_event: import("../db/schema/safelink").SafelinkEvent;
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/mod-service/status.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAEvC,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAQ7C,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAA;AAuMxE,eAAO,MAAM,mCAAmC,GAAI,IAAI,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wcAyDrE,CAAA;AAKD,eAAO,MAAM,6BAA6B,GACxC,IAAI,QAAQ,EACZ,iBAAiB,kBAAkB,EACnC,WAAW,MAAM,EAAE,KAClB,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAiO3C,CAAA;AAED,eAAO,MAAM,8BAA8B,GACzC,SAAS,MAAM,GAAG,KAAK,KACtB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAkBnC,CAAA"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/mod-service/status.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAEvC,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAQ7C,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAA;AAuMxE,eAAO,MAAM,mCAAmC,GAAI,IAAI,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wcAyDrE,CAAA;AAKD,eAAO,MAAM,6BAA6B,GACxC,IAAI,QAAQ,EACZ,iBAAiB,kBAAkB,EACnC,WAAW,MAAM,EAAE,KAClB,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAiO3C,CAAA;AAED,eAAO,MAAM,8BAA8B,GACzC,SAAS,MAAM,GAAG,KAAK,KACtB;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAkBnC,CAAA"}
@@ -0,0 +1,86 @@
1
+ import { Selectable } from 'kysely';
2
+ import { ToolsOzoneQueueDefs } from '@atproto/api';
3
+ import { Database } from '../db';
4
+ import { ReportQueue } from '../db/schema/report_queue';
5
+ export type QueueServiceCreator = (db: Database) => QueueService;
6
+ export declare class QueueService {
7
+ db: Database;
8
+ constructor(db: Database);
9
+ static creator(): (db: Database) => QueueService;
10
+ checkConflict({ subjectTypes, collection, reportTypes, excludeId, }: {
11
+ subjectTypes: string[];
12
+ collection?: string | null;
13
+ reportTypes: string[];
14
+ excludeId?: number;
15
+ }): Promise<void>;
16
+ create({ name, subjectTypes, collection, reportTypes, description, createdBy, }: {
17
+ name: string;
18
+ subjectTypes: string[];
19
+ collection?: string | null;
20
+ reportTypes: string[];
21
+ description?: string | null;
22
+ createdBy: string;
23
+ }): Promise<Selectable<ReportQueue>>;
24
+ getById(id: number): Promise<Selectable<ReportQueue> | undefined>;
25
+ getViewsByIds(ids: number[]): Promise<Map<number, ToolsOzoneQueueDefs.QueueView>>;
26
+ update(id: number, updates: {
27
+ name?: string;
28
+ enabled?: boolean;
29
+ description?: string;
30
+ }): Promise<Selectable<ReportQueue>>;
31
+ delete(id: number): Promise<void>;
32
+ migrateReports(fromQueueId: number, toQueueId?: number): Promise<number>;
33
+ list({ limit, cursor, enabled, subjectType, collection, reportTypes, }: {
34
+ limit: number;
35
+ cursor?: string;
36
+ enabled?: boolean;
37
+ subjectType?: string;
38
+ collection?: string;
39
+ reportTypes?: string[];
40
+ }): Promise<{
41
+ queues: Selectable<ReportQueue>[];
42
+ cursor?: string;
43
+ }>;
44
+ view(queue: Selectable<ReportQueue>): ToolsOzoneQueueDefs.QueueView;
45
+ viewsWithStats(queues: Selectable<ReportQueue>[]): Promise<ToolsOzoneQueueDefs.QueueView[]>;
46
+ /**
47
+ * Re-route a range of existing reports against the current queue config.
48
+ * Used by the manual `tools.ozone.queue.routeReports` endpoint to pick up
49
+ * reports after queues are created or modified. New reports are inserted
50
+ * by the daemon via `insertReportsFromEvents`, not here.
51
+ */
52
+ assignReportBatch(params: {
53
+ start: number;
54
+ end: number;
55
+ limit: number;
56
+ }, opts?: {
57
+ includeUnmatched?: boolean;
58
+ serviceDid?: string;
59
+ }): Promise<{
60
+ processed: number;
61
+ assigned: number;
62
+ unmatched: number;
63
+ maxId: number;
64
+ }>;
65
+ /**
66
+ * Read newly-created modEventReport rows from `moderation_event` and
67
+ * insert corresponding `report` rows with `queueId` already resolved.
68
+ * Used by the queue-router daemon. Idempotent via `ON CONFLICT (eventId)
69
+ * DO NOTHING` — safe to re-run on the same range.
70
+ *
71
+ * Even when no queues are configured, report rows are still inserted with
72
+ * `queueId = -1` so the invariant "every modEventReport has a `report` row"
73
+ * holds.
74
+ */
75
+ insertReportsFromEvents(params: {
76
+ cursor: number | null;
77
+ limit: number;
78
+ }): Promise<{
79
+ processed: number;
80
+ assigned: number;
81
+ unmatched: number;
82
+ maxEventId: number;
83
+ }>;
84
+ }
85
+ export declare function findMatchingQueue(queues: Selectable<ReportQueue>[], subjectType: string, collection: string | null, reportType: string | undefined): Selectable<ReportQueue> | null;
86
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/queue/service.ts"],"names":[],"mappings":"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"}