@atproto/ozone 0.2.4 → 0.2.6

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 (217) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/api/index.d.ts.map +1 -1
  3. package/dist/api/index.js +2 -0
  4. package/dist/api/index.js.map +1 -1
  5. package/dist/api/label/queryLabels.d.ts.map +1 -1
  6. package/dist/api/label/queryLabels.js +13 -21
  7. package/dist/api/label/queryLabels.js.map +1 -1
  8. package/dist/api/report/queryActivities.d.ts +4 -0
  9. package/dist/api/report/queryActivities.d.ts.map +1 -0
  10. package/dist/api/report/queryActivities.js +36 -0
  11. package/dist/api/report/queryActivities.js.map +1 -0
  12. package/dist/assignment/index.d.ts.map +1 -1
  13. package/dist/assignment/index.js +9 -12
  14. package/dist/assignment/index.js.map +1 -1
  15. package/dist/background.d.ts +5 -3
  16. package/dist/background.d.ts.map +1 -1
  17. package/dist/background.js +13 -4
  18. package/dist/background.js.map +1 -1
  19. package/dist/context.js +1 -1
  20. package/dist/context.js.map +1 -1
  21. package/dist/daemon/context.js +1 -1
  22. package/dist/daemon/context.js.map +1 -1
  23. package/dist/daemon/event-pusher.d.ts +7 -1
  24. package/dist/daemon/event-pusher.d.ts.map +1 -1
  25. package/dist/daemon/verification-listener.d.ts +1 -1
  26. package/dist/daemon/verification-listener.d.ts.map +1 -1
  27. package/dist/daemon/verification-listener.js +10 -4
  28. package/dist/daemon/verification-listener.js.map +1 -1
  29. package/dist/db/index.d.ts +4 -5
  30. package/dist/db/index.d.ts.map +1 -1
  31. package/dist/db/index.js +2 -1
  32. package/dist/db/index.js.map +1 -1
  33. package/dist/db/migrations/20241220T144630860Z-stats-materialized-views.d.ts +1 -2
  34. package/dist/db/migrations/20241220T144630860Z-stats-materialized-views.d.ts.map +1 -1
  35. package/dist/db/migrations/20241220T144630860Z-stats-materialized-views.js.map +1 -1
  36. package/dist/db/migrations/20250718T150931000Z-update-appeal-reason-stats.d.ts +1 -2
  37. package/dist/db/migrations/20250718T150931000Z-update-appeal-reason-stats.d.ts.map +1 -1
  38. package/dist/db/migrations/20250718T150931000Z-update-appeal-reason-stats.js.map +1 -1
  39. package/dist/db/migrations/20260602T120000000Z-add-report-activity-created-index.d.ts +4 -0
  40. package/dist/db/migrations/20260602T120000000Z-add-report-activity-created-index.d.ts.map +1 -0
  41. package/dist/db/migrations/20260602T120000000Z-add-report-activity-created-index.js +15 -0
  42. package/dist/db/migrations/20260602T120000000Z-add-report-activity-created-index.js.map +1 -0
  43. package/dist/db/migrations/index.d.ts +1 -0
  44. package/dist/db/migrations/index.d.ts.map +1 -1
  45. package/dist/db/migrations/index.js +1 -0
  46. package/dist/db/migrations/index.js.map +1 -1
  47. package/dist/db/migrations/provider.d.ts +2 -1
  48. package/dist/db/migrations/provider.d.ts.map +1 -1
  49. package/dist/db/migrations/provider.js.map +1 -1
  50. package/dist/db/pagination.d.ts +4 -3
  51. package/dist/db/pagination.d.ts.map +1 -1
  52. package/dist/db/pagination.js +4 -4
  53. package/dist/db/pagination.js.map +1 -1
  54. package/dist/db/types.d.ts +1 -1
  55. package/dist/db/types.d.ts.map +1 -1
  56. package/dist/db/types.js.map +1 -1
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +23 -13
  59. package/dist/index.js.map +1 -1
  60. package/dist/jetstream/service.d.ts +1 -1
  61. package/dist/jetstream/service.d.ts.map +1 -1
  62. package/dist/jetstream/service.js +3 -1
  63. package/dist/jetstream/service.js.map +1 -1
  64. package/dist/lexicon/index.d.ts +11 -0
  65. package/dist/lexicon/index.d.ts.map +1 -1
  66. package/dist/lexicon/index.js +18 -0
  67. package/dist/lexicon/index.js.map +1 -1
  68. package/dist/lexicon/lexicons.d.ts +338 -0
  69. package/dist/lexicon/lexicons.d.ts.map +1 -1
  70. package/dist/lexicon/lexicons.js +173 -0
  71. package/dist/lexicon/lexicons.js.map +1 -1
  72. package/dist/lexicon/types/app/bsky/notification/defs.d.ts +1 -0
  73. package/dist/lexicon/types/app/bsky/notification/defs.d.ts.map +1 -1
  74. package/dist/lexicon/types/app/bsky/notification/defs.js.map +1 -1
  75. package/dist/lexicon/types/chat/bsky/notification/defs.d.ts +19 -0
  76. package/dist/lexicon/types/chat/bsky/notification/defs.d.ts.map +1 -0
  77. package/dist/lexicon/types/chat/bsky/notification/defs.js +19 -0
  78. package/dist/lexicon/types/chat/bsky/notification/defs.js.map +1 -0
  79. package/dist/lexicon/types/chat/bsky/notification/getPreferences.d.ts +20 -0
  80. package/dist/lexicon/types/chat/bsky/notification/getPreferences.d.ts.map +1 -0
  81. package/dist/lexicon/types/chat/bsky/notification/getPreferences.js +5 -0
  82. package/dist/lexicon/types/chat/bsky/notification/getPreferences.js.map +1 -0
  83. package/dist/lexicon/types/chat/bsky/notification/putPreferences.d.ts +26 -0
  84. package/dist/lexicon/types/chat/bsky/notification/putPreferences.d.ts.map +1 -0
  85. package/dist/lexicon/types/chat/bsky/notification/putPreferences.js +5 -0
  86. package/dist/lexicon/types/chat/bsky/notification/putPreferences.js.map +1 -0
  87. package/dist/lexicon/types/tools/ozone/report/defs.d.ts +1 -0
  88. package/dist/lexicon/types/tools/ozone/report/defs.d.ts.map +1 -1
  89. package/dist/lexicon/types/tools/ozone/report/defs.js.map +1 -1
  90. package/dist/lexicon/types/tools/ozone/report/queryActivities.d.ts +32 -0
  91. package/dist/lexicon/types/tools/ozone/report/queryActivities.d.ts.map +1 -0
  92. package/dist/lexicon/types/tools/ozone/report/queryActivities.js +5 -0
  93. package/dist/lexicon/types/tools/ozone/report/queryActivities.js.map +1 -0
  94. package/dist/mod-service/index.d.ts.map +1 -1
  95. package/dist/mod-service/index.js +28 -52
  96. package/dist/mod-service/index.js.map +1 -1
  97. package/dist/mod-service/report.d.ts +1 -0
  98. package/dist/mod-service/report.d.ts.map +1 -1
  99. package/dist/mod-service/report.js +16 -0
  100. package/dist/mod-service/report.js.map +1 -1
  101. package/dist/mod-service/status.d.ts +23 -128
  102. package/dist/mod-service/status.d.ts.map +1 -1
  103. package/dist/mod-service/views.js +7 -11
  104. package/dist/mod-service/views.js.map +1 -1
  105. package/dist/queue/service.js +1 -3
  106. package/dist/queue/service.js.map +1 -1
  107. package/dist/report/activity.d.ts +31 -2
  108. package/dist/report/activity.d.ts.map +1 -1
  109. package/dist/report/activity.js +27 -1
  110. package/dist/report/activity.js.map +1 -1
  111. package/dist/report/stats.d.ts.map +1 -1
  112. package/dist/report/stats.js.map +1 -1
  113. package/dist/scheduled-action/service.d.ts.map +1 -1
  114. package/dist/scheduled-action/service.js +16 -20
  115. package/dist/scheduled-action/service.js.map +1 -1
  116. package/dist/set/service.d.ts +10 -1
  117. package/dist/set/service.d.ts.map +1 -1
  118. package/dist/set/service.js +5 -2
  119. package/dist/set/service.js.map +1 -1
  120. package/dist/team/index.d.ts.map +1 -1
  121. package/dist/team/index.js +5 -4
  122. package/dist/team/index.js.map +1 -1
  123. package/dist/verification/issuer.d.ts +13 -3
  124. package/dist/verification/issuer.d.ts.map +1 -1
  125. package/dist/verification/service.d.ts +13 -1
  126. package/dist/verification/service.d.ts.map +1 -1
  127. package/dist/verification/service.js +1 -1
  128. package/dist/verification/service.js.map +1 -1
  129. package/package.json +12 -11
  130. package/src/api/index.ts +2 -0
  131. package/src/api/label/queryLabels.ts +11 -14
  132. package/src/api/report/queryActivities.ts +64 -0
  133. package/src/assignment/index.ts +15 -18
  134. package/src/background.ts +19 -4
  135. package/src/context.ts +1 -1
  136. package/src/daemon/context.ts +1 -1
  137. package/src/daemon/verification-listener.ts +9 -4
  138. package/src/db/index.ts +1 -1
  139. package/src/db/migrations/20241220T144630860Z-stats-materialized-views.ts +1 -2
  140. package/src/db/migrations/20250718T150931000Z-update-appeal-reason-stats.ts +1 -2
  141. package/src/db/migrations/20260602T120000000Z-add-report-activity-created-index.ts +17 -0
  142. package/src/db/migrations/index.ts +1 -0
  143. package/src/db/migrations/provider.ts +2 -1
  144. package/src/db/pagination.ts +18 -18
  145. package/src/db/types.ts +3 -1
  146. package/src/index.ts +25 -15
  147. package/src/jetstream/service.ts +3 -1
  148. package/src/mod-service/index.ts +78 -71
  149. package/src/mod-service/report.ts +24 -3
  150. package/src/mod-service/views.ts +16 -16
  151. package/src/queue/service.ts +5 -5
  152. package/src/report/activity.ts +47 -0
  153. package/src/report/stats.ts +5 -3
  154. package/src/scheduled-action/service.ts +22 -20
  155. package/src/set/service.ts +17 -14
  156. package/src/team/index.ts +6 -5
  157. package/src/verification/service.ts +2 -2
  158. package/tests/3p-labeler.test.ts +2 -2
  159. package/tests/_util.ts +8 -25
  160. package/tests/account-strikes.test.ts +1 -1
  161. package/tests/ack-all-subjects-of-account.test.ts +1 -1
  162. package/tests/age-assurance.test.ts +1 -1
  163. package/tests/blob-divert.test.ts +1 -1
  164. package/tests/communication-templates.test.ts +1 -1
  165. package/tests/content-tagger.test.ts +1 -1
  166. package/tests/db.test.ts +1 -1
  167. package/tests/expiring-label.test.ts +1 -1
  168. package/tests/expiring-tags.test.ts +1 -1
  169. package/tests/get-account-timeline.test.ts +1 -1
  170. package/tests/get-config.test.ts +1 -1
  171. package/tests/get-lists.test.ts +2 -1
  172. package/tests/get-profiles.test.ts +1 -1
  173. package/tests/get-record.test.ts +1 -1
  174. package/tests/get-records.test.ts +1 -1
  175. package/tests/get-repo.test.ts +1 -1
  176. package/tests/get-report.test.ts +1 -1
  177. package/tests/get-reporter-stats.test.ts +1 -1
  178. package/tests/get-repos.test.ts +1 -1
  179. package/tests/get-starter-pack.test.ts +1 -1
  180. package/tests/get-subjects.test.ts +1 -1
  181. package/tests/mod-tool.test.ts +1 -1
  182. package/tests/moderation-appeals.test.ts +1 -1
  183. package/tests/moderation-events.test.ts +1 -1
  184. package/tests/moderation-status-tags.test.ts +1 -1
  185. package/tests/moderation-statuses.test.ts +1 -1
  186. package/tests/moderation.test.ts +1 -1
  187. package/tests/protected-tags.test.ts +1 -1
  188. package/tests/query-labels.test.ts +1 -1
  189. package/tests/query-reports.test.ts +1 -1
  190. package/tests/queue-assignment.test.ts +1 -1
  191. package/tests/queue-router.test.ts +1 -1
  192. package/tests/queues.test.ts +1 -1
  193. package/tests/record-and-account-events.test.ts +1 -1
  194. package/tests/repo-search.test.ts +2 -2
  195. package/tests/report-action.test.ts +1 -1
  196. package/tests/report-activity.test.ts +145 -1
  197. package/tests/report-assignment.test.ts +1 -1
  198. package/tests/report-muting.test.ts +1 -1
  199. package/tests/report-reason.test.ts +1 -1
  200. package/tests/report-reassign-queue.test.ts +1 -1
  201. package/tests/report-routing.test.ts +1 -1
  202. package/tests/report-stats.test.ts +1 -1
  203. package/tests/revoke-account-credentials.test.ts +1 -1
  204. package/tests/safelink.test.ts +1 -1
  205. package/tests/scheduled-action-processor.test.ts +1 -1
  206. package/tests/scheduled-action.test.ts +1 -1
  207. package/tests/sequencer.test.ts +1 -1
  208. package/tests/server.test.ts +9 -12
  209. package/tests/sets.test.ts +1 -1
  210. package/tests/settings.test.ts +1 -1
  211. package/tests/strike-expiry-processor.test.ts +1 -1
  212. package/tests/subject-priority-score.test.ts +1 -1
  213. package/tests/takedown.test.ts +1 -1
  214. package/tests/team.test.ts +1 -1
  215. package/tests/verification-listener.test.ts +40 -13
  216. package/tests/verification.test.ts +1 -1
  217. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/report/stats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,GAAG,EAAE,MAAM,QAAQ,CAAA;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAExC,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAElE,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEvC;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAA6B;IAC1D,MAAM,EAAE;QACN,wCAAwC;QACxC,6CAA6C;QAC7C,8CAA8C;QAC9C,0CAA0C;QAC1C,wCAAwC;QACxC,yCAAyC;QACzC,0CAA0C;KAC3C;IACD,MAAM,EAAE,CAAC,sCAAsC,CAAC;IAChD,QAAQ,EAAE;QACR,qDAAqD;QACrD,+CAA+C;QAC/C,sDAAsD;QACtD,gDAAgD;QAChD,qDAAqD;QACrD,wDAAwD;QACxD,mDAAmD;QACnD,6CAA6C;KAC9C;IACD,MAAM,EAAE;QACN,kDAAkD;QAClD,0CAA0C;QAC1C,gDAAgD;QAChD,8CAA8C;QAC9C,4CAA4C;QAC5C,+CAA+C;QAC/C,2CAA2C;KAC5C;IACD,cAAc,EAAE;QACd,+CAA+C;QAC/C,gDAAgD;QAChD,uDAAuD;QACvD,uDAAuD;QACvD,qDAAqD;QACrD,oDAAoD;QACpD,gDAAgD;KACjD;IACD,UAAU,EAAE;QACV,+CAA+C;QAC/C,kDAAkD;QAClD,oDAAoD;QACpD,iDAAiD;QACjD,+CAA+C;KAChD;IACD,UAAU,EAAE;QACV,6CAA6C;QAC7C,uDAAuD;QACvD,8CAA8C;QAC9C,8CAA8C;QAC9C,0DAA0D;QAC1D,wDAAwD;QACxD,+CAA+C;KAChD;IACD,iBAAiB,EAAE;QACjB,gDAAgD;QAChD,iDAAiD;QACjD,mDAAmD;QACnD,8CAA8C;QAC9C,yCAAyC;KAC1C;IACD,KAAK,EAAE;QACL,qDAAqD;QACrD,+CAA+C;QAC/C,iDAAiD;QACjD,mDAAmD;QACnD,kDAAkD;KACnD;CACF,CAAA;AAED,MAAM,oBAAoB,GAAG,EAAE,GAAG,MAAM,CAAA;AAkGxC,MAAM,OAAO,kBAAkB;IAC7B,YAAmB,EAAY;kBAAZ,EAAE;IAAa,CAAC;IAEnC,MAAM,CAAC,OAAO;QACZ,OAAO,CAAC,EAAY,EAAE,EAAE,CAAC,IAAI,kBAAkB,CAAC,EAAE,CAAC,CAAA;IACrD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,cAAc,CAAC,IAA0B;QAC7C,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YACxB,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;YACtC,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAA;YAE1E,+BAA+B;YAC/B,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;YAEvC,yDAAyD;YACzD,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;gBACjB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;qBAClC,UAAU,CAAC,aAAa,CAAC;qBACzB,MAAM,CAAC,YAAY,CAAC;qBACpB,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,CAAC;qBAC7B,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC;qBAC7B,gBAAgB,EAAE,CAAA;gBACrB,MAAM,cAAc,GAAG,IAAI,IAAI,CAAC,GAAG,SAAS,gBAAgB,CAAC,CAAC,OAAO,EAAE,CAAA;gBACvE,IACE,CAAC,YAAY;oBACb,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,GAAG,cAAc,EAC5D,CAAC;oBACD,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;gBACxD,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;YACxD,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAA;YACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,wCAAwC,CAAC,CAAA;QACvE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,sCAAsC,CAAC,CAAA;QACjE,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,IAItB;QACC,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACtC,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAElC,KAAK,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;YACzE,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,CAAA;YAC/B,IAAI,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;gBAC1B,qDAAqD;gBACrD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAA;gBACvD,MAAM,IAAI,GAAgB,EAAE,CAAA;gBAC5B,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACpC,MAAM,KAAK,GAAoB;wBAC7B,OAAO;wBACP,YAAY,EAAE,IAAI;wBAClB,WAAW,EAAE,IAAI;qBAClB,CAAA;oBACD,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;oBACpD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;gBACvD,CAAC;gBACD,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YAC7B,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;YACtD,CAAC;QACH,CAAC;IACH,CAAC;IAED,sDAAsD;IAC9C,KAAK,CAAC,eAAe,CAC3B,IAAY,EACZ,IAA0B;QAE1B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE,CAAA;QAC3C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAA;QACpD,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;QACtC,MAAM,OAAO,GAAG,IAAI,KAAK,KAAK,CAAA;QAE9B,gEAAgE;QAChE,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,KAAK;YAChC,CAAC,CAAC,MAAM,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC;YAC1C,CAAC,CAAC,IAAI,CAAA;QAER,MAAM,IAAI,GAAgB,EAAE,CAAA;QAC5B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,IAAI,aAAa,EAAE,CAAC;oBAClB,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;oBACjD,IAAI,MAAM,EAAE,CAAC;wBACX,gEAAgE;wBAChE,IAAI,CAAC,OAAO;4BAAE,SAAQ;wBACtB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAA;wBAC9D,IAAI,GAAG,GAAG,oBAAoB;4BAAE,SAAQ;oBAC1C,CAAC;gBACH,CAAC;gBACD,MAAM,KAAK,GAAG,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;gBACpD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;YACpD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,QAAQ,CAAC,KAAK,CACZ,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EACpB,oCAAoC,CACrC,CAAA;YACH,CAAC;QACH,CAAC;QAED,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;IAC7B,CAAC;IAED,yEAAyE;IACjE,KAAK,CAAC,uBAAuB,CACnC,IAAY;QAEZ,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aAC9B,UAAU,CAAC,aAAa,CAAC;aACzB,SAAS,EAAE;aACX,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC;aACxB,OAAO,EAAE,CAAA;QACZ,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkC,CAAA;QACrD,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,GAAG,CAAC,GAAG,CACL,QAAQ,CAAC;gBACP,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,YAAY,EAAE,GAAG,CAAC,YAAY;gBAC9B,WAAW,EAAE,GAAG,CAAC,WAAW;aAC7B,CAAC,EACF,GAAG,CACJ,CAAA;QACH,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,gDAAgD;IACxC,KAAK,CAAC,eAAe;QAC3B,MAAM,MAAM,GAAsB,EAAE,CAAA;QAEpC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aAC5B,UAAU,CAAC,cAAc,CAAC;aAC1B,SAAS,EAAE;aACX,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC;aAC3B,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC;aAC9B,OAAO,EAAE,CAAA;QACZ,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aAC7B,UAAU,CAAC,QAAQ,CAAC;aACpB,MAAM,CAAC,KAAK,CAAC;aACb,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,KAAK,CAAC;aAC7B,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE;YACnB,iCAAiC;YACjC,qCAAqC;YACrC,kCAAkC;SACnC,CAAC;aACD,OAAO,EAAE,CAAA;QAEZ,YAAY;QACZ,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAA;QACrE,YAAY;QACZ,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3E,CAAC;QACD,WAAW;QACX,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAA;QACnE,gBAAgB;QAChB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,CAAC,IAAI,CAAC;gBACV,OAAO,EAAE,IAAI;gBACb,YAAY,EAAE,MAAM,CAAC,GAAG;gBACxB,WAAW,EAAE,IAAI;aAClB,CAAC,CAAA;QACJ,CAAC;QACD,wBAAwB;QACxB,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC3D,MAAM,CAAC,IAAI,CAAC;gBACV,OAAO,EAAE,IAAI;gBACb,YAAY,EAAE,IAAI;gBAClB,WAAW,EAAE,UAAU;aACxB,CAAC,CAAA;QACJ,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,mBAAmB,CAAC,IAAY;QAC5C,MAAM,QAAQ,GAAG,GAAG,IAAI,gBAAgB,CAAA;QACxC,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAA;QAEhD,MAAM,CAAC,YAAY,EAAE,gBAAgB,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACzD,+EAA+E;YAC/E,IAAI,CAAC,EAAE,CAAC,EAAE;iBACP,UAAU,CAAC,QAAQ,CAAC;iBACpB,MAAM,CAAC,CAAC,SAAS,EAAE,GAAG,CAAQ,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;iBACtD,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC;iBAC/B,KAAK,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC;iBAChC,OAAO,CAAC,SAAS,CAAC;iBAClB,OAAO,EAAE;YACZ,2DAA2D;YAC3D,IAAI,CAAC,EAAE,CAAC,EAAE;iBACP,UAAU,CAAC,QAAQ,CAAC;iBACpB,MAAM,CAAC,GAAG,CAAQ,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;iBACzC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC;iBAC/B,gBAAgB,EAAE;SACtB,CAAC,CAAA;QAEF,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aACjC,UAAU,CAAC,QAAQ,CAAC;aACpB,MAAM,CAAC;YACN,SAAS;YACT,GAAG,CAAQ,UAAU,CAAC,EAAE,CAAC,cAAc,CAAC;YACxC,GAAG,CAAQ,gEAAgE,QAAQ,qBAAqB,MAAM,GAAG,CAAC,EAAE,CAClH,eAAe,CAChB;YACD,GAAG,CAAQ,gDAAgD,CAAC,EAAE,CAC5D,gBAAgB,CACjB;YACD,GAAG,CAAQ,4JAA4J,QAAQ,qBAAqB,MAAM,GAAG,CAAC,EAAE,CAC9M,iBAAiB,CAClB;YACD,GAAG,CAAQ,2FAA2F,QAAQ,qBAAqB,MAAM,GAAG,CAAC,EAAE,CAC7I,mBAAmB,CACpB;SACF,CAAC;aACD,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,QAAQ,CAAC;aAClC,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,MAAM,CAAC;aAC/B,KAAK,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC;aAChC,OAAO,CAAC,SAAS,CAAC;aAClB,OAAO,EAAE,CAAA;QAEZ,4CAA4C;QAC5C,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aACrC,UAAU,CAAC,QAAQ,CAAC;aACpB,MAAM,CAAC;YACN,GAAG,CAAQ,UAAU,CAAC,EAAE,CAAC,cAAc,CAAC;YACxC,GAAG,CAAQ,gEAAgE,QAAQ,qBAAqB,MAAM,GAAG,CAAC,EAAE,CAClH,eAAe,CAChB;YACD,GAAG,CAAQ,gDAAgD,CAAC,EAAE,CAC5D,gBAAgB,CACjB;YACD,GAAG,CAAQ,4JAA4J,QAAQ,qBAAqB,MAAM,GAAG,CAAC,EAAE,CAC9M,iBAAiB,CAClB;YACD,GAAG,CAAQ,2FAA2F,QAAQ,qBAAqB,MAAM,GAAG,CAAC,EAAE,CAC7I,mBAAmB,CACpB;SACF,CAAC;aACD,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,QAAQ,CAAC;aAClC,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,MAAM,CAAC;aAC/B,gBAAgB,EAAE,CAAA;QAErB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aACjC,UAAU,CAAC,QAAQ,CAAC;aACpB,MAAM,CAAC,CAAC,YAAY,EAAE,GAAG,CAAQ,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;aACzD,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC;aAC/B,OAAO,CAAC,YAAY,CAAC;aACrB,OAAO,EAAE,CAAA;QAEZ,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aAChC,UAAU,CAAC,QAAQ,CAAC;aACpB,MAAM,CAAC;YACN,YAAY;YACZ,GAAG,CAAQ,UAAU,CAAC,EAAE,CAAC,cAAc,CAAC;YACxC,GAAG,CAAQ,gEAAgE,QAAQ,qBAAqB,MAAM,GAAG,CAAC,EAAE,CAClH,eAAe,CAChB;YACD,GAAG,CAAQ,gDAAgD,CAAC,EAAE,CAC5D,gBAAgB,CACjB;YACD,GAAG,CAAQ,4JAA4J,QAAQ,qBAAqB,MAAM,GAAG,CAAC,EAAE,CAC9M,iBAAiB,CAClB;YACD,GAAG,CAAQ,2FAA2F,QAAQ,qBAAqB,MAAM,GAAG,CAAC,EAAE,CAC7I,mBAAmB,CACpB;SACF,CAAC;aACD,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,QAAQ,CAAC;aAClC,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,MAAM,CAAC;aAC/B,OAAO,CAAC,YAAY,CAAC;aACrB,OAAO,EAAE,CAAA;QAEZ,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aAC/B,UAAU,CAAC,aAAa,CAAC;aACzB,SAAS,CAAC,4BAA4B,EAAE,CAAC,IAAI,EAAE,EAAE,CAChD,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,CAClE;aACA,MAAM,CAAC;YACN,QAAQ;YACR,GAAG,CAAQ,UAAU,CAAC,EAAE,CAAC,cAAc,CAAC;YACxC,GAAG,CAAQ,+CAA+C,CAAC,EAAE,CAC3D,eAAe,CAChB;YACD,GAAG,CAAQ,gJAAgJ,CAAC,EAAE,CAC5J,iBAAiB,CAClB;YACD,GAAG,CAAQ,4EAA4E,CAAC,EAAE,CACxF,mBAAmB,CACpB;SACF,CAAC;aACD,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,QAAQ,CAAC;aACpC,KAAK,CAAC,aAAa,EAAE,GAAG,EAAE,MAAM,CAAC;aACjC,OAAO,CAAC,QAAQ,CAAC;aACjB,OAAO,EAAE,CAAA;QAEZ,yFAAyF;QACzF,MAAM,eAAe,GAAoB;YACvC,GAAG,YAAY;YACf,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,IAAI,GAAG,EAAE;SACzD,CAAA;QACD,MAAM,cAAc,GAAqB,eAAe;YACtD,CAAC,CAAC;gBACE,GAAG,WAAW;gBACd;oBACE,OAAO,EAAE,IAAI;oBACb,YAAY,EAAE,eAAe,CAAC,YAAY;oBAC1C,aAAa,EAAE,eAAe,CAAC,aAAa;oBAC5C,cAAc,EAAE,eAAe,CAAC,cAAc;oBAC9C,eAAe,EAAE,eAAe,CAAC,eAAe;oBAChD,iBAAiB,EAAE,eAAe,CAAC,iBAAiB;iBACrD;aACF;YACH,CAAC,CAAC,WAAW,CAAA;QAEf,OAAO;YACL,YAAY,EAAE,eAAe;YAC7B,WAAW,EAAE,cAAc;YAC3B,WAAW;YACX,UAAU;YACV,SAAS;SACV,CAAA;IACH,CAAC;IAED,kFAAkF;IAC1E,iBAAiB,CACvB,KAAsB,EACtB,OAAqB;QAErB,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,YAAY,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;QAC1E,CAAC;QACD,IAAI,KAAK,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QAChE,CAAC;QACD,OAAO,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IACvD,CAAC;IAEO,iBAAiB,CACvB,OAAsB,EACtB,OAAqB;QAErB,8CAA8C;QAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAA;QACvE,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAA;QAErE,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QACxC,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;QAC9C,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;QAChD,MAAM,cAAc,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;QAClD,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,IAAI,CAAC,CAAC,CAAA;QAC5D,MAAM,iBAAiB,GAAG,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;QACxD,MAAM,UAAU,GACd,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,aAAa,GAAG,YAAY,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACzE,MAAM,kBAAkB,GACtB,iBAAiB,GAAG,CAAC;YACnB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,iBAAiB,CAAC;YACjD,CAAC,CAAC,SAAS,CAAA;QAEf,OAAO;YACL,YAAY;YACZ,YAAY;YACZ,aAAa;YACb,cAAc;YACd,UAAU;YACV,kBAAkB;SACnB,CAAA;IACH,CAAC;IAEO,sBAAsB,CAC5B,WAAqB,EACrB,OAAqB;QAErB,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAA;QAElC,MAAM,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACvD,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CACxB,CAAA;QACD,MAAM,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACrD,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CACxB,CAAA;QAED,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;QACrD,MAAM,YAAY,GAAG,MAAM,CAAC,cAAc,EAAE,cAAc,CAAC,CAAA;QAC3D,MAAM,aAAa,GAAG,MAAM,CAAC,cAAc,EAAE,eAAe,CAAC,CAAA;QAC7D,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAA;QAC/D,MAAM,eAAe,GAAG,cAAc,CAAC,MAAM,CAC3C,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,EAChD,CAAC,CACF,CAAA;QACD,MAAM,iBAAiB,GAAG,MAAM,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAA;QAErE,MAAM,UAAU,GACd,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,aAAa,GAAG,YAAY,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACzE,MAAM,kBAAkB,GACtB,iBAAiB,GAAG,CAAC;YACnB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,iBAAiB,CAAC;YACjD,CAAC,CAAC,SAAS,CAAA;QAEf,OAAO;YACL,YAAY;YACZ,YAAY;YACZ,aAAa;YACb,cAAc;YACd,UAAU;YACV,kBAAkB;SACnB,CAAA;IACH,CAAC;IAEO,qBAAqB,CAC3B,YAAoB,EACpB,IAA0B;QAE1B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,YAAY,CAAC,CAAA;QAEpD,MAAM,YAAY,GAAG,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAA;QAC3C,MAAM,aAAa,GAAG,GAAG,CAAC,GAAG,EAAE,aAAa,CAAC,CAAA;QAC7C,MAAM,iBAAiB,GAAG,GAAG,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAA;QACrD,MAAM,kBAAkB,GACtB,iBAAiB,GAAG,CAAC,IAAI,GAAG,EAAE,eAAe;YAC3C,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,iBAAiB,CAAC;YAC7D,CAAC,CAAC,SAAS,CAAA;QAEf,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,CAAA;IAC5D,CAAC;IAED,qDAAqD;IAC7C,cAAc,CACpB,IAAY,EACZ,KAAsB,EACtB,KAAuB;QAEvB,MAAM,YAAY,GAChB,cAAc,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;QAC7D,MAAM,cAAc,GAClB,gBAAgB,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;QACjE,MAAM,UAAU,GAAG,YAAY,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;QAE1E,OAAO;YACL,IAAI;YACJ,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,IAAI;YACxC,YAAY;YACZ,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,IAAI;YAC1C,cAAc;YACd,UAAU;YACV,kBAAkB,EAAE,KAAK,CAAC,kBAAkB,IAAI,IAAI;YACpD,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACrC,CAAA;IACH,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,UAAU,CAAC,IAAiB;QACxC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAM;QAExB,MAAM,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACxC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;gBACrB,IAAI,GAAG,GAAG,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;gBACvE,GAAG;oBACD,CAAC,CAAC,OAAO,KAAK,IAAI;wBAChB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC;wBACtC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;gBACtC,GAAG;oBACD,CAAC,CAAC,YAAY,KAAK,IAAI;wBACrB,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC,YAAY,CAAC;wBAChD,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;gBAC3C,GAAG;oBACD,CAAC,CAAC,WAAW,KAAK,IAAI;wBACpB,CAAC,CAAC,GAAG,CAAC,KAAK,CACP,GAAG,CAAA,0BAA0B,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,CAC3D;wBACH,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;gBAC1C,MAAM,GAAG,CAAC,OAAO,EAAE,CAAA;gBAEnB,MAAM,KAAK,CAAC,EAAE;qBACX,UAAU,CAAC,aAAa,CAAC;qBACzB,MAAM,CAAC;oBACN,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,OAAO,EAAE,CAAC,CAAC,OAAO;oBAClB,YAAY,EAAE,CAAC,CAAC,YAAY;oBAC5B,WAAW,EAAE,CAAC,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI;oBACjE,YAAY,EAAE,CAAC,CAAC,YAAY;oBAC5B,YAAY,EAAE,CAAC,CAAC,YAAY;oBAC5B,aAAa,EAAE,CAAC,CAAC,aAAa;oBAC9B,cAAc,EAAE,CAAC,CAAC,cAAc;oBAChC,UAAU,EAAE,CAAC,CAAC,UAAU;oBACxB,kBAAkB,EAAE,CAAC,CAAC,kBAAkB;oBACxC,UAAU,EAAE,CAAC,CAAC,UAAU;iBACzB,CAAC;qBACD,OAAO,EAAE,CAAA;YACd,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,uBAAuB;IAEvB,gDAAgD;IACxC,KAAK,CAAC,cAAc,CAC1B,IAAY,EACZ,KAAsB;QAEtB,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE;aAChB,UAAU,CAAC,aAAa,CAAC;aACzB,SAAS,EAAE;aACX,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;QAC3B,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAC3B,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;QAC9C,CAAC;aAAM,CAAC;YACN,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;QACtC,CAAC;QACD,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YACvB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,EAAE,KAAK,CAAC,YAAY,CAAC,CAAA;QACxD,CAAC;aAAM,CAAC;YACN,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;QAC3C,CAAC;QACD,IAAI,KAAK,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;YAC/B,EAAE,GAAG,EAAE,CAAC,KAAK,CACX,GAAG,CAAA,0BAA0B,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,CAC/D,CAAA;QACH,CAAC;aAAM,CAAC;YACN,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;QAC1C,CAAC;QACD,OAAO,EAAE,CAAC,gBAAgB,EAAE,CAAA;IAC9B,CAAC;IAED,0CAA0C;IAC1C,KAAK,CAAC,YAAY,CAChB,KAAsB;QAEtB,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;QACtC,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;IAC1C,CAAC;IAED,4DAA4D;IAC5D,KAAK,CAAC,qBAAqB,CACzB,QAAkB;QAElB,IAAI,CAAC,QAAQ,CAAC,MAAM;YAAE,OAAO,IAAI,GAAG,EAAE,CAAA;QAEtC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;QACtC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aAC1B,UAAU,CAAC,aAAa,CAAC;aACzB,SAAS,EAAE;aACX,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC;aACzB,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC;aAChC,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC;aACjC,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC;aAChC,OAAO,EAAE,CAAA;QAEZ,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkC,CAAA;QACxD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;gBACzB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;YAC9B,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED,wDAAwD;IACxD,KAAK,CAAC,kBAAkB,CAAC,IAMxB;QACC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,CAAA;QACjD,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,KAAK,CAAA;QACpD,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAA;QAElC,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,SAAS,EAAE,CAAA;QAEzD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC,CAAA;QACxC,CAAC;aAAM,CAAC;YACN,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;QACtC,CAAC;QACD,IAAI,YAAY,EAAE,CAAC;YACjB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,EAAE,YAAY,CAAC,CAAA;QAClD,CAAC;aAAM,CAAC;YACN,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;QAC3C,CAAC;QACD,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACzB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAA,0BAA0B,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;QACzE,CAAC;aAAM,CAAC;YACN,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;QAC1C,CAAC;QACD,IAAI,SAAS,EAAE,CAAC;YACd,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;QAChE,CAAC;QACD,IAAI,OAAO,EAAE,CAAC;YACZ,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QAC9D,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,kBAAkB,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;QACnE,MAAM,gBAAgB,GAAG,QAAQ,CAAC,EAAE,EAAE;YACpC,KAAK;YACL,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM;YACN,SAAS,EAAE,MAAM;YACjB,QAAQ,EAAE,IAAI;SACf,CAAC,CAAA;QAEF,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,CAAA;QAE9C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAA;IACxD,CAAC;CACF;AAED,kBAAkB;AAElB,2DAA2D;AAC3D,SAAS,GAAG,CAAC,GAA8B;IACzC,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAC9B,CAAC;AAED,8CAA8C;AAC9C,SAAS,MAAM,CAAI,IAAS,EAAE,KAAc;IAC1C,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAChE,CAAC;AAED;;;;GAIG;AACH,SAAS,QAAQ,CAAC,CAAkB;IAClC,OAAO;QACL,CAAC,CAAC,OAAO,IAAI,MAAM;QACnB,CAAC,CAAC,YAAY,IAAI,MAAM;QACxB,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM;KACvD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACb,CAAC;AAED,yDAAyD;AACzD,SAAS,YAAY,CAAC,CAAO;IAC3B,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AACrC,CAAC;AAED,yCAAyC;AACzC,SAAS,QAAQ,CAAC,OAAe;IAC/B,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,OAAO,gBAAgB,CAAC,CAAA;IAC9C,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAA;IAChC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAA;AACxB,CAAC","sourcesContent":["import { Selectable, sql } from 'kysely'\nimport { MINUTE } from '@atproto/common'\nimport { Database } from '../db/index.js'\nimport { ComputedAtIdKeyset, paginate } from '../db/pagination.js'\nimport { ReportStat } from '../db/schema/report_stat.js'\nimport { jsonb } from '../db/types.js'\nimport { dbLogger } from '../logger.js'\n\n/**\n * Grouped report types. Stats are computed per group rather than per individual report type.\n */\nexport const REPORT_TYPE_GROUPS: Record<string, string[]> = {\n Legacy: [\n 'com.atproto.moderation.defs#reasonSpam',\n 'com.atproto.moderation.defs#reasonViolation',\n 'com.atproto.moderation.defs#reasonMisleading',\n 'com.atproto.moderation.defs#reasonSexual',\n 'com.atproto.moderation.defs#reasonRude',\n 'com.atproto.moderation.defs#reasonOther',\n 'com.atproto.moderation.defs#reasonAppeal',\n ],\n Appeal: ['tools.ozone.report.defs#reasonAppeal'],\n Violence: [\n 'tools.ozone.report.defs#reasonViolenceAnimalWelfare',\n 'tools.ozone.report.defs#reasonViolenceThreats',\n 'tools.ozone.report.defs#reasonViolenceGraphicContent',\n 'tools.ozone.report.defs#reasonViolenceSelfHarm',\n 'tools.ozone.report.defs#reasonViolenceGlorification',\n 'tools.ozone.report.defs#reasonViolenceExtremistContent',\n 'tools.ozone.report.defs#reasonViolenceTrafficking',\n 'tools.ozone.report.defs#reasonViolenceOther',\n ],\n Sexual: [\n 'tools.ozone.report.defs#reasonSexualAbuseContent',\n 'tools.ozone.report.defs#reasonSexualNCII',\n 'tools.ozone.report.defs#reasonSexualSextortion',\n 'tools.ozone.report.defs#reasonSexualDeepfake',\n 'tools.ozone.report.defs#reasonSexualAnimal',\n 'tools.ozone.report.defs#reasonSexualUnlabeled',\n 'tools.ozone.report.defs#reasonSexualOther',\n ],\n 'Child Safety': [\n 'tools.ozone.report.defs#reasonChildSafetyCSAM',\n 'tools.ozone.report.defs#reasonChildSafetyGroom',\n 'tools.ozone.report.defs#reasonChildSafetyMinorPrivacy',\n 'tools.ozone.report.defs#reasonChildSafetyEndangerment',\n 'tools.ozone.report.defs#reasonChildSafetyHarassment',\n 'tools.ozone.report.defs#reasonChildSafetyPromotion',\n 'tools.ozone.report.defs#reasonChildSafetyOther',\n ],\n Harassment: [\n 'tools.ozone.report.defs#reasonHarassmentTroll',\n 'tools.ozone.report.defs#reasonHarassmentTargeted',\n 'tools.ozone.report.defs#reasonHarassmentHateSpeech',\n 'tools.ozone.report.defs#reasonHarassmentDoxxing',\n 'tools.ozone.report.defs#reasonHarassmentOther',\n ],\n Misleading: [\n 'tools.ozone.report.defs#reasonMisleadingBot',\n 'tools.ozone.report.defs#reasonMisleadingImpersonation',\n 'tools.ozone.report.defs#reasonMisleadingSpam',\n 'tools.ozone.report.defs#reasonMisleadingScam',\n 'tools.ozone.report.defs#reasonMisleadingSyntheticContent',\n 'tools.ozone.report.defs#reasonMisleadingMisinformation',\n 'tools.ozone.report.defs#reasonMisleadingOther',\n ],\n 'Rule Violations': [\n 'tools.ozone.report.defs#reasonRuleSiteSecurity',\n 'tools.ozone.report.defs#reasonRuleStolenContent',\n 'tools.ozone.report.defs#reasonRuleProhibitedSales',\n 'tools.ozone.report.defs#reasonRuleBanEvasion',\n 'tools.ozone.report.defs#reasonRuleOther',\n ],\n Civic: [\n 'tools.ozone.report.defs#reasonCivicElectoralProcess',\n 'tools.ozone.report.defs#reasonCivicDisclosure',\n 'tools.ozone.report.defs#reasonCivicInterference',\n 'tools.ozone.report.defs#reasonCivicMisinformation',\n 'tools.ozone.report.defs#reasonCivicImpersonation',\n ],\n}\n\nconst REPORT_STAT_LIVE_TTL = 15 * MINUTE\n\nexport type ReportStatsServiceCreator = (db: Database) => ReportStatsService\n\nexport type ReportStatGroup = {\n queueId: number | null\n moderatorDid: string | null\n reportTypes: string[] | null\n}\nexport type AggregateStatistics = {\n inboundCount: number\n pendingCount: number\n actionedCount: number\n escalatedCount: number\n actionRate: number\n avgHandlingTimeSec?: number\n}\nexport type QueueStatistics = {\n inboundCount: number\n pendingCount: number\n actionedCount: number\n escalatedCount: number\n actionRate: number\n avgHandlingTimeSec?: number\n}\nexport type ModeratorStatistics = {\n inboundCount: number\n actionedCount: number\n avgHandlingTimeSec?: number\n}\nexport type ReportTypeStatistics = {\n inboundCount: number\n pendingCount: number\n actionedCount: number\n escalatedCount: number\n actionRate: number\n avgHandlingTimeSec?: number\n}\nexport type ReportStatistics =\n | QueueStatistics\n | ModeratorStatistics\n | AggregateStatistics\n | ReportTypeStatistics\n\n// Batched query result types\ntype QueueCountRow = {\n queueId: number | null\n count: string\n}\ntype QueueWindowRow = {\n queueId: number | null\n inboundCount: string\n actionedCount: string\n escalatedCount: string\n handlingTimeSum: string | null\n handlingTimeCount: string\n}\ntype TypeCountRow = {\n reportType: string\n count: string\n}\ntype TypeWindowRow = {\n reportType: string\n inboundCount: string\n actionedCount: string\n escalatedCount: string\n handlingTimeSum: string | null\n handlingTimeCount: string\n}\ntype ModeratorWindowRow = {\n did: string\n inboundCount: string\n actionedCount: string\n handlingTimeSum: string | null\n handlingTimeCount: string\n}\ntype BatchedStats = {\n queuePending: QueueCountRow[]\n queueWindow: QueueWindowRow[]\n typePending: TypeCountRow[]\n typeWindow: TypeWindowRow[]\n moderator: ModeratorWindowRow[]\n}\n\ntype UpsertRow = {\n date: string\n queueId: number | null\n moderatorDid: string | null\n reportTypes: string[] | null\n inboundCount: number | null\n pendingCount: number | null\n actionedCount: number | null\n escalatedCount: number | null\n actionRate: number | null\n avgHandlingTimeSec: number | null\n computedAt: string\n}\n\nexport class ReportStatsService {\n constructor(public db: Database) {}\n\n static creator(): ReportStatsServiceCreator {\n return (db: Database) => new ReportStatsService(db)\n }\n\n /**\n * Compute stats for today and finalize yesterday if needed.\n * Called periodically by the StatsComputer daemon.\n */\n async materializeAll(opts?: { force?: boolean }): Promise<void> {\n try {\n const start = Date.now()\n const today = toDateString(new Date())\n const yesterday = toDateString(new Date(Date.now() - 24 * 60 * 60 * 1000))\n\n // Always compute today's stats\n await this.materializeDate(today, opts)\n\n // Finalize yesterday if its snapshot is missing or stale\n if (!opts?.force) {\n const yesterdayRow = await this.db.db\n .selectFrom('report_stat')\n .select('computedAt')\n .where('date', '=', yesterday)\n .orderBy('computedAt', 'desc')\n .executeTakeFirst()\n const endOfYesterday = new Date(`${yesterday}T23:59:59.999Z`).getTime()\n if (\n !yesterdayRow ||\n new Date(yesterdayRow.computedAt).getTime() < endOfYesterday\n ) {\n await this.materializeDate(yesterday, { force: true })\n }\n } else {\n await this.materializeDate(yesterday, { force: true })\n }\n\n const duration = Date.now() - start\n dbLogger.info({ duration }, 'report stats materialization completed')\n } catch (err) {\n dbLogger.error({ err }, 'report stats materialization errored')\n }\n }\n\n /**\n * Compute stats for a specific date range. Used by the refreshStats endpoint.\n */\n async refreshDateRange(opts: {\n startDate: string\n endDate: string\n queueIds?: number[]\n }): Promise<void> {\n const start = new Date(opts.startDate)\n const end = new Date(opts.endDate)\n\n for (let d = new Date(start); d <= end; d.setUTCDate(d.getUTCDate() + 1)) {\n const dateStr = toDateString(d)\n if (opts.queueIds?.length) {\n // Recompute only specific queue groups for this date\n const batched = await this.computeBatchedStats(dateStr)\n const rows: UpsertRow[] = []\n for (const queueId of opts.queueIds) {\n const group: ReportStatGroup = {\n queueId,\n moderatorDid: null,\n reportTypes: null,\n }\n const stats = this.resolveGroupStats(group, batched)\n rows.push(this.buildUpsertRow(dateStr, group, stats))\n }\n await this.bulkUpsert(rows)\n } else {\n await this.materializeDate(dateStr, { force: true })\n }\n }\n }\n\n /** Compute and write all groups for a single date. */\n private async materializeDate(\n date: string,\n opts?: { force?: boolean },\n ): Promise<void> {\n const groups = await this.enumerateGroups()\n const batched = await this.computeBatchedStats(date)\n const today = toDateString(new Date())\n const isToday = date === today\n\n // Batch the cache check so we don't issue one SELECT per group.\n const existingByKey = !opts?.force\n ? await this.fetchExistingStatsByKey(date)\n : null\n\n const rows: UpsertRow[] = []\n for (const group of groups) {\n try {\n if (existingByKey) {\n const cached = existingByKey.get(groupKey(group))\n if (cached) {\n // Historical dates: never recompute. Today: recompute if stale.\n if (!isToday) continue\n const age = Date.now() - new Date(cached.computedAt).getTime()\n if (age < REPORT_STAT_LIVE_TTL) continue\n }\n }\n const stats = this.resolveGroupStats(group, batched)\n rows.push(this.buildUpsertRow(date, group, stats))\n } catch (err) {\n dbLogger.error(\n { err, group, date },\n 'error preparing report stats group',\n )\n }\n }\n\n await this.bulkUpsert(rows)\n }\n\n /** Fetch all stat rows for a date, keyed by groupKey for O(1) lookup. */\n private async fetchExistingStatsByKey(\n date: string,\n ): Promise<Map<string, Selectable<ReportStat>>> {\n const existing = await this.db.db\n .selectFrom('report_stat')\n .selectAll()\n .where('date', '=', date)\n .execute()\n const map = new Map<string, Selectable<ReportStat>>()\n for (const row of existing) {\n map.set(\n groupKey({\n queueId: row.queueId,\n moderatorDid: row.moderatorDid,\n reportTypes: row.reportTypes,\n }),\n row,\n )\n }\n return map\n }\n\n /** List out the groups to compute stats for. */\n private async enumerateGroups(): Promise<ReportStatGroup[]> {\n const groups: ReportStatGroup[] = []\n\n const queues = await this.db.db\n .selectFrom('report_queue')\n .selectAll()\n .where('enabled', '=', true)\n .where('deletedAt', 'is', null)\n .execute()\n const members = await this.db.db\n .selectFrom('member')\n .select('did')\n .where('disabled', '=', false)\n .where('role', 'in', [\n 'tools.ozone.team.defs#roleAdmin',\n 'tools.ozone.team.defs#roleModerator',\n 'tools.ozone.team.defs#roleTriage',\n ])\n .execute()\n\n // aggregate\n groups.push({ queueId: null, moderatorDid: null, reportTypes: null })\n // per queue\n for (const queue of queues) {\n groups.push({ queueId: queue.id, moderatorDid: null, reportTypes: null })\n }\n // unqueued\n groups.push({ queueId: -1, moderatorDid: null, reportTypes: null })\n // per moderator\n for (const member of members) {\n groups.push({\n queueId: null,\n moderatorDid: member.did,\n reportTypes: null,\n })\n }\n // per report type group\n for (const groupTypes of Object.values(REPORT_TYPE_GROUPS)) {\n groups.push({\n queueId: null,\n moderatorDid: null,\n reportTypes: groupTypes,\n })\n }\n\n return groups\n }\n\n /**\n * Run batched GROUP BY queries for a calendar date.\n * Returns 5 result sets covering all group types.\n */\n private async computeBatchedStats(date: string): Promise<BatchedStats> {\n const dayStart = `${date}T00:00:00.000Z`\n const dayEnd = `${nextDate(date)}T00:00:00.000Z`\n\n const [queuePending, aggregatePending] = await Promise.all([\n // Pending count is a snapshot of all non-closed reports at time of computation\n this.db.db\n .selectFrom('report')\n .select(['queueId', sql<string>`count(*)`.as('count')])\n .where('status', '!=', 'closed')\n .where('queueId', 'is not', null)\n .groupBy('queueId')\n .execute(),\n // Aggregate pending (includes all reports, even un-routed)\n this.db.db\n .selectFrom('report')\n .select(sql<string>`count(*)`.as('count'))\n .where('status', '!=', 'closed')\n .executeTakeFirst(),\n ])\n\n const queueWindow = await this.db.db\n .selectFrom('report')\n .select([\n 'queueId',\n sql<string>`count(*)`.as('inboundCount'),\n sql<string>`count(*) filter (where \"status\" = 'closed' and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'actionedCount',\n ),\n sql<string>`count(*) filter (where \"status\" = 'escalated')`.as(\n 'escalatedCount',\n ),\n sql<string>`sum(extract(epoch from (\"closedAt\"::timestamp - \"createdAt\"::timestamp))) filter (where \"status\" = 'closed' and \"closedAt\" is not null and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'handlingTimeSum',\n ),\n sql<string>`count(*) filter (where \"status\" = 'closed' and \"closedAt\" is not null and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'handlingTimeCount',\n ),\n ])\n .where('createdAt', '>=', dayStart)\n .where('createdAt', '<', dayEnd)\n .where('queueId', 'is not', null)\n .groupBy('queueId')\n .execute()\n\n // Aggregate windowed (includes all reports)\n const aggregateWindow = await this.db.db\n .selectFrom('report')\n .select([\n sql<string>`count(*)`.as('inboundCount'),\n sql<string>`count(*) filter (where \"status\" = 'closed' and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'actionedCount',\n ),\n sql<string>`count(*) filter (where \"status\" = 'escalated')`.as(\n 'escalatedCount',\n ),\n sql<string>`sum(extract(epoch from (\"closedAt\"::timestamp - \"createdAt\"::timestamp))) filter (where \"status\" = 'closed' and \"closedAt\" is not null and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'handlingTimeSum',\n ),\n sql<string>`count(*) filter (where \"status\" = 'closed' and \"closedAt\" is not null and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'handlingTimeCount',\n ),\n ])\n .where('createdAt', '>=', dayStart)\n .where('createdAt', '<', dayEnd)\n .executeTakeFirst()\n\n const typePending = await this.db.db\n .selectFrom('report')\n .select(['reportType', sql<string>`count(*)`.as('count')])\n .where('status', '!=', 'closed')\n .groupBy('reportType')\n .execute()\n\n const typeWindow = await this.db.db\n .selectFrom('report')\n .select([\n 'reportType',\n sql<string>`count(*)`.as('inboundCount'),\n sql<string>`count(*) filter (where \"status\" = 'closed' and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'actionedCount',\n ),\n sql<string>`count(*) filter (where \"status\" = 'escalated')`.as(\n 'escalatedCount',\n ),\n sql<string>`sum(extract(epoch from (\"closedAt\"::timestamp - \"createdAt\"::timestamp))) filter (where \"status\" = 'closed' and \"closedAt\" is not null and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'handlingTimeSum',\n ),\n sql<string>`count(*) filter (where \"status\" = 'closed' and \"closedAt\" is not null and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'handlingTimeCount',\n ),\n ])\n .where('createdAt', '>=', dayStart)\n .where('createdAt', '<', dayEnd)\n .groupBy('reportType')\n .execute()\n\n const moderator = await this.db.db\n .selectFrom('report as r')\n .innerJoin('moderator_assignment as ma', (join) =>\n join.onRef('ma.reportId', '=', 'r.id').on('ma.endAt', 'is', null),\n )\n .select([\n 'ma.did',\n sql<string>`count(*)`.as('inboundCount'),\n sql<string>`count(*) filter (where r.\"status\" = 'closed')`.as(\n 'actionedCount',\n ),\n sql<string>`sum(extract(epoch from (r.\"closedAt\"::timestamp - ma.\"startAt\"::timestamp))) filter (where r.\"status\" = 'closed' and r.\"closedAt\" is not null)`.as(\n 'handlingTimeSum',\n ),\n sql<string>`count(*) filter (where r.\"status\" = 'closed' and r.\"closedAt\" is not null)`.as(\n 'handlingTimeCount',\n ),\n ])\n .where('r.createdAt', '>=', dayStart)\n .where('r.createdAt', '<', dayEnd)\n .groupBy('ma.did')\n .execute()\n\n // Inject aggregate as a synthetic row with queueId=null so resolveQueueStats can find it\n const allQueuePending: QueueCountRow[] = [\n ...queuePending,\n { queueId: null, count: aggregatePending?.count ?? '0' },\n ]\n const allQueueWindow: QueueWindowRow[] = aggregateWindow\n ? [\n ...queueWindow,\n {\n queueId: null,\n inboundCount: aggregateWindow.inboundCount,\n actionedCount: aggregateWindow.actionedCount,\n escalatedCount: aggregateWindow.escalatedCount,\n handlingTimeSum: aggregateWindow.handlingTimeSum,\n handlingTimeCount: aggregateWindow.handlingTimeCount,\n },\n ]\n : queueWindow\n\n return {\n queuePending: allQueuePending,\n queueWindow: allQueueWindow,\n typePending,\n typeWindow,\n moderator,\n }\n }\n\n /** Resolve a single group's stats from batched query results (pure in-memory). */\n private resolveGroupStats(\n group: ReportStatGroup,\n batched: BatchedStats,\n ): ReportStatistics {\n if (group.moderatorDid) {\n return this.resolveModeratorStats(group.moderatorDid, batched.moderator)\n }\n if (group.reportTypes !== null) {\n return this.resolveReportTypeStats(group.reportTypes, batched)\n }\n return this.resolveQueueStats(group.queueId, batched)\n }\n\n private resolveQueueStats(\n queueId: number | null,\n batched: BatchedStats,\n ): AggregateStatistics | QueueStatistics {\n // queueId=null is the synthetic aggregate row\n const pending = batched.queuePending.find((r) => r.queueId === queueId)\n const window = batched.queueWindow.find((r) => r.queueId === queueId)\n\n const pendingCount = num(pending?.count)\n const inboundCount = num(window?.inboundCount)\n const actionedCount = num(window?.actionedCount)\n const escalatedCount = num(window?.escalatedCount)\n const handlingTimeSum = Number(window?.handlingTimeSum ?? 0)\n const handlingTimeCount = num(window?.handlingTimeCount)\n const actionRate =\n inboundCount > 0 ? Math.round((actionedCount / inboundCount) * 100) : 0\n const avgHandlingTimeSec =\n handlingTimeCount > 0\n ? Math.round(handlingTimeSum / handlingTimeCount)\n : undefined\n\n return {\n inboundCount,\n pendingCount,\n actionedCount,\n escalatedCount,\n actionRate,\n avgHandlingTimeSec,\n }\n }\n\n private resolveReportTypeStats(\n reportTypes: string[],\n batched: BatchedStats,\n ): ReportTypeStatistics {\n const types = new Set(reportTypes)\n\n const matchingPending = batched.typePending.filter((r) =>\n types.has(r.reportType),\n )\n const matchingWindow = batched.typeWindow.filter((r) =>\n types.has(r.reportType),\n )\n\n const pendingCount = sumNum(matchingPending, 'count')\n const inboundCount = sumNum(matchingWindow, 'inboundCount')\n const actionedCount = sumNum(matchingWindow, 'actionedCount')\n const escalatedCount = sumNum(matchingWindow, 'escalatedCount')\n const handlingTimeSum = matchingWindow.reduce(\n (sum, r) => sum + Number(r.handlingTimeSum ?? 0),\n 0,\n )\n const handlingTimeCount = sumNum(matchingWindow, 'handlingTimeCount')\n\n const actionRate =\n inboundCount > 0 ? Math.round((actionedCount / inboundCount) * 100) : 0\n const avgHandlingTimeSec =\n handlingTimeCount > 0\n ? Math.round(handlingTimeSum / handlingTimeCount)\n : undefined\n\n return {\n inboundCount,\n pendingCount,\n actionedCount,\n escalatedCount,\n actionRate,\n avgHandlingTimeSec,\n }\n }\n\n private resolveModeratorStats(\n moderatorDid: string,\n rows: ModeratorWindowRow[],\n ): ModeratorStatistics {\n const row = rows.find((r) => r.did === moderatorDid)\n\n const inboundCount = num(row?.inboundCount)\n const actionedCount = num(row?.actionedCount)\n const handlingTimeCount = num(row?.handlingTimeCount)\n const avgHandlingTimeSec =\n handlingTimeCount > 0 && row?.handlingTimeSum\n ? Math.round(Number(row.handlingTimeSum) / handlingTimeCount)\n : undefined\n\n return { inboundCount, actionedCount, avgHandlingTimeSec }\n }\n\n /** Build an upsert row from (date, group, stats). */\n private buildUpsertRow(\n date: string,\n group: ReportStatGroup,\n stats: ReportStatistics,\n ): UpsertRow {\n const pendingCount =\n 'pendingCount' in stats ? stats.pendingCount ?? null : null\n const escalatedCount =\n 'escalatedCount' in stats ? stats.escalatedCount ?? null : null\n const actionRate = 'actionRate' in stats ? stats.actionRate ?? null : null\n\n return {\n date,\n queueId: group.queueId,\n moderatorDid: group.moderatorDid,\n reportTypes: group.reportTypes,\n inboundCount: stats.inboundCount ?? null,\n pendingCount,\n actionedCount: stats.actionedCount ?? null,\n escalatedCount,\n actionRate,\n avgHandlingTimeSec: stats.avgHandlingTimeSec ?? null,\n computedAt: new Date().toISOString(),\n }\n }\n\n /**\n * Wraps a DELETE+INSERT for each row in a single transaction so we pay one\n * commit per cycle instead of one per group. NULL-aware WHERE clauses match\n * the existing PG <15 NULL semantics without needing a unique index.\n */\n private async bulkUpsert(rows: UpsertRow[]): Promise<void> {\n if (!rows.length) return\n\n await this.db.transaction(async (dbTxn) => {\n for (const r of rows) {\n let del = dbTxn.db.deleteFrom('report_stat').where('date', '=', r.date)\n del =\n r.queueId !== null\n ? del.where('queueId', '=', r.queueId)\n : del.where('queueId', 'is', null)\n del =\n r.moderatorDid !== null\n ? del.where('moderatorDid', '=', r.moderatorDid)\n : del.where('moderatorDid', 'is', null)\n del =\n r.reportTypes !== null\n ? del.where(\n sql`\"reportTypes\"::jsonb = ${jsonb(r.reportTypes)}::jsonb`,\n )\n : del.where('reportTypes', 'is', null)\n await del.execute()\n\n await dbTxn.db\n .insertInto('report_stat')\n .values({\n date: r.date,\n queueId: r.queueId,\n moderatorDid: r.moderatorDid,\n reportTypes: r.reportTypes !== null ? jsonb(r.reportTypes) : null,\n inboundCount: r.inboundCount,\n pendingCount: r.pendingCount,\n actionedCount: r.actionedCount,\n escalatedCount: r.escalatedCount,\n actionRate: r.actionRate,\n avgHandlingTimeSec: r.avgHandlingTimeSec,\n computedAt: r.computedAt,\n })\n .execute()\n }\n })\n }\n\n // ─── Read methods ───\n\n /** Get a single stat row for a date + group. */\n private async getStatForDate(\n date: string,\n group: ReportStatGroup,\n ): Promise<Selectable<ReportStat> | undefined> {\n let qb = this.db.db\n .selectFrom('report_stat')\n .selectAll()\n .where('date', '=', date)\n if (group.queueId !== null) {\n qb = qb.where('queueId', '=', group.queueId)\n } else {\n qb = qb.where('queueId', 'is', null)\n }\n if (group.moderatorDid) {\n qb = qb.where('moderatorDid', '=', group.moderatorDid)\n } else {\n qb = qb.where('moderatorDid', 'is', null)\n }\n if (group.reportTypes !== null) {\n qb = qb.where(\n sql`\"reportTypes\"::jsonb = ${jsonb(group.reportTypes)}::jsonb`,\n )\n } else {\n qb = qb.where('reportTypes', 'is', null)\n }\n return qb.executeTakeFirst()\n }\n\n /** Get today's live stats for a group. */\n async getLiveStats(\n group: ReportStatGroup,\n ): Promise<Selectable<ReportStat> | undefined> {\n const today = toDateString(new Date())\n return this.getStatForDate(today, group)\n }\n\n /** Get live stats for multiple queues in a single query. */\n async getLiveStatsForQueues(\n queueIds: number[],\n ): Promise<Map<number, Selectable<ReportStat>>> {\n if (!queueIds.length) return new Map()\n\n const today = toDateString(new Date())\n const rows = await this.db.db\n .selectFrom('report_stat')\n .selectAll()\n .where('date', '=', today)\n .where('queueId', 'in', queueIds)\n .where('moderatorDid', 'is', null)\n .where('reportTypes', 'is', null)\n .execute()\n\n const result = new Map<number, Selectable<ReportStat>>()\n for (const row of rows) {\n if (row.queueId !== null) {\n result.set(row.queueId, row)\n }\n }\n return result\n }\n\n /** Get historical stats for a date range, paginated. */\n async getHistoricalStats(opts: {\n group: ReportStatGroup\n startDate?: string\n endDate?: string\n limit: number\n cursor?: string\n }): Promise<{ stats: Selectable<ReportStat>[]; cursor?: string }> {\n const { group, startDate, endDate, limit } = opts\n const { queueId, moderatorDid, reportTypes } = group\n const { ref } = this.db.db.dynamic\n\n let qb = this.db.db.selectFrom('report_stat').selectAll()\n\n if (queueId !== null) {\n qb = qb.where('queueId', '=', queueId)\n } else {\n qb = qb.where('queueId', 'is', null)\n }\n if (moderatorDid) {\n qb = qb.where('moderatorDid', '=', moderatorDid)\n } else {\n qb = qb.where('moderatorDid', 'is', null)\n }\n if (reportTypes !== null) {\n qb = qb.where(sql`\"reportTypes\"::jsonb = ${jsonb(reportTypes)}::jsonb`)\n } else {\n qb = qb.where('reportTypes', 'is', null)\n }\n if (startDate) {\n qb = qb.where('date', '>=', toDateString(new Date(startDate)))\n }\n if (endDate) {\n qb = qb.where('date', '<=', toDateString(new Date(endDate)))\n }\n\n const keyset = new ComputedAtIdKeyset(ref('computedAt'), ref('id'))\n const paginatedBuilder = paginate(qb, {\n limit,\n cursor: opts.cursor,\n keyset,\n direction: 'desc',\n tryIndex: true,\n })\n\n const stats = await paginatedBuilder.execute()\n\n return { stats, cursor: keyset.packFromResult(stats) }\n }\n}\n\n// ─── Helpers ───\n\n/** Parse a pg bigint string to number, defaulting to 0. */\nfunction num(val: string | undefined | null): number {\n return val ? Number(val) : 0\n}\n\n/** Sum a numeric string field across rows. */\nfunction sumNum<T>(rows: T[], field: keyof T): number {\n return rows.reduce((sum, r) => sum + Number(r[field] ?? 0), 0)\n}\n\n/**\n * Stable cache-key for a stat group. Used to look up an existing row in the\n * batched cache map without issuing per-group SELECTs. Report types are\n * stringified in stored order, which matches REPORT_TYPE_GROUPS.\n */\nfunction groupKey(g: ReportStatGroup): string {\n return [\n g.queueId ?? 'null',\n g.moderatorDid ?? 'null',\n g.reportTypes ? JSON.stringify(g.reportTypes) : 'null',\n ].join('|')\n}\n\n/** Convert a Date to an ISO date string (YYYY-MM-DD). */\nfunction toDateString(d: Date): string {\n return d.toISOString().slice(0, 10)\n}\n\n/** Get the next calendar date string. */\nfunction nextDate(dateStr: string): string {\n const d = new Date(`${dateStr}T00:00:00.000Z`)\n d.setUTCDate(d.getUTCDate() + 1)\n return toDateString(d)\n}\n"]}
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/report/stats.ts"],"names":[],"mappings":"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","sourcesContent":["import { Selectable, sql } from 'kysely'\nimport { MINUTE } from '@atproto/common'\nimport { Database } from '../db/index.js'\nimport { ComputedAtIdKeyset, paginate } from '../db/pagination.js'\nimport { ReportStat } from '../db/schema/report_stat.js'\nimport { jsonb } from '../db/types.js'\nimport { dbLogger } from '../logger.js'\n\n/**\n * Grouped report types. Stats are computed per group rather than per individual report type.\n */\nexport const REPORT_TYPE_GROUPS: Record<string, string[]> = {\n Legacy: [\n 'com.atproto.moderation.defs#reasonSpam',\n 'com.atproto.moderation.defs#reasonViolation',\n 'com.atproto.moderation.defs#reasonMisleading',\n 'com.atproto.moderation.defs#reasonSexual',\n 'com.atproto.moderation.defs#reasonRude',\n 'com.atproto.moderation.defs#reasonOther',\n 'com.atproto.moderation.defs#reasonAppeal',\n ],\n Appeal: ['tools.ozone.report.defs#reasonAppeal'],\n Violence: [\n 'tools.ozone.report.defs#reasonViolenceAnimalWelfare',\n 'tools.ozone.report.defs#reasonViolenceThreats',\n 'tools.ozone.report.defs#reasonViolenceGraphicContent',\n 'tools.ozone.report.defs#reasonViolenceSelfHarm',\n 'tools.ozone.report.defs#reasonViolenceGlorification',\n 'tools.ozone.report.defs#reasonViolenceExtremistContent',\n 'tools.ozone.report.defs#reasonViolenceTrafficking',\n 'tools.ozone.report.defs#reasonViolenceOther',\n ],\n Sexual: [\n 'tools.ozone.report.defs#reasonSexualAbuseContent',\n 'tools.ozone.report.defs#reasonSexualNCII',\n 'tools.ozone.report.defs#reasonSexualSextortion',\n 'tools.ozone.report.defs#reasonSexualDeepfake',\n 'tools.ozone.report.defs#reasonSexualAnimal',\n 'tools.ozone.report.defs#reasonSexualUnlabeled',\n 'tools.ozone.report.defs#reasonSexualOther',\n ],\n 'Child Safety': [\n 'tools.ozone.report.defs#reasonChildSafetyCSAM',\n 'tools.ozone.report.defs#reasonChildSafetyGroom',\n 'tools.ozone.report.defs#reasonChildSafetyMinorPrivacy',\n 'tools.ozone.report.defs#reasonChildSafetyEndangerment',\n 'tools.ozone.report.defs#reasonChildSafetyHarassment',\n 'tools.ozone.report.defs#reasonChildSafetyPromotion',\n 'tools.ozone.report.defs#reasonChildSafetyOther',\n ],\n Harassment: [\n 'tools.ozone.report.defs#reasonHarassmentTroll',\n 'tools.ozone.report.defs#reasonHarassmentTargeted',\n 'tools.ozone.report.defs#reasonHarassmentHateSpeech',\n 'tools.ozone.report.defs#reasonHarassmentDoxxing',\n 'tools.ozone.report.defs#reasonHarassmentOther',\n ],\n Misleading: [\n 'tools.ozone.report.defs#reasonMisleadingBot',\n 'tools.ozone.report.defs#reasonMisleadingImpersonation',\n 'tools.ozone.report.defs#reasonMisleadingSpam',\n 'tools.ozone.report.defs#reasonMisleadingScam',\n 'tools.ozone.report.defs#reasonMisleadingSyntheticContent',\n 'tools.ozone.report.defs#reasonMisleadingMisinformation',\n 'tools.ozone.report.defs#reasonMisleadingOther',\n ],\n 'Rule Violations': [\n 'tools.ozone.report.defs#reasonRuleSiteSecurity',\n 'tools.ozone.report.defs#reasonRuleStolenContent',\n 'tools.ozone.report.defs#reasonRuleProhibitedSales',\n 'tools.ozone.report.defs#reasonRuleBanEvasion',\n 'tools.ozone.report.defs#reasonRuleOther',\n ],\n Civic: [\n 'tools.ozone.report.defs#reasonCivicElectoralProcess',\n 'tools.ozone.report.defs#reasonCivicDisclosure',\n 'tools.ozone.report.defs#reasonCivicInterference',\n 'tools.ozone.report.defs#reasonCivicMisinformation',\n 'tools.ozone.report.defs#reasonCivicImpersonation',\n ],\n}\n\nconst REPORT_STAT_LIVE_TTL = 15 * MINUTE\n\nexport type ReportStatsServiceCreator = (db: Database) => ReportStatsService\n\nexport type ReportStatGroup = {\n queueId: number | null\n moderatorDid: string | null\n reportTypes: string[] | null\n}\nexport type AggregateStatistics = {\n inboundCount: number\n pendingCount: number\n actionedCount: number\n escalatedCount: number\n actionRate: number\n avgHandlingTimeSec?: number\n}\nexport type QueueStatistics = {\n inboundCount: number\n pendingCount: number\n actionedCount: number\n escalatedCount: number\n actionRate: number\n avgHandlingTimeSec?: number\n}\nexport type ModeratorStatistics = {\n inboundCount: number\n actionedCount: number\n avgHandlingTimeSec?: number\n}\nexport type ReportTypeStatistics = {\n inboundCount: number\n pendingCount: number\n actionedCount: number\n escalatedCount: number\n actionRate: number\n avgHandlingTimeSec?: number\n}\nexport type ReportStatistics =\n | QueueStatistics\n | ModeratorStatistics\n | AggregateStatistics\n | ReportTypeStatistics\n\n// Batched query result types\ntype QueueCountRow = {\n queueId: number | null\n count: string\n}\ntype QueueWindowRow = {\n queueId: number | null\n inboundCount: string\n actionedCount: string\n escalatedCount: string\n handlingTimeSum: string | null\n handlingTimeCount: string\n}\ntype TypeCountRow = {\n reportType: string\n count: string\n}\ntype TypeWindowRow = {\n reportType: string\n inboundCount: string\n actionedCount: string\n escalatedCount: string\n handlingTimeSum: string | null\n handlingTimeCount: string\n}\ntype ModeratorWindowRow = {\n did: string\n inboundCount: string\n actionedCount: string\n handlingTimeSum: string | null\n handlingTimeCount: string\n}\ntype BatchedStats = {\n queuePending: QueueCountRow[]\n queueWindow: QueueWindowRow[]\n typePending: TypeCountRow[]\n typeWindow: TypeWindowRow[]\n moderator: ModeratorWindowRow[]\n}\n\ntype UpsertRow = {\n date: string\n queueId: number | null\n moderatorDid: string | null\n reportTypes: string[] | null\n inboundCount: number | null\n pendingCount: number | null\n actionedCount: number | null\n escalatedCount: number | null\n actionRate: number | null\n avgHandlingTimeSec: number | null\n computedAt: string\n}\n\nexport class ReportStatsService {\n constructor(public db: Database) {}\n\n static creator(): ReportStatsServiceCreator {\n return (db: Database) => new ReportStatsService(db)\n }\n\n /**\n * Compute stats for today and finalize yesterday if needed.\n * Called periodically by the StatsComputer daemon.\n */\n async materializeAll(opts?: { force?: boolean }): Promise<void> {\n try {\n const start = Date.now()\n const today = toDateString(new Date())\n const yesterday = toDateString(new Date(Date.now() - 24 * 60 * 60 * 1000))\n\n // Always compute today's stats\n await this.materializeDate(today, opts)\n\n // Finalize yesterday if its snapshot is missing or stale\n if (!opts?.force) {\n const yesterdayRow = await this.db.db\n .selectFrom('report_stat')\n .select('computedAt')\n .where('date', '=', yesterday)\n .orderBy('computedAt', 'desc')\n .executeTakeFirst()\n const endOfYesterday = new Date(`${yesterday}T23:59:59.999Z`).getTime()\n if (\n !yesterdayRow ||\n new Date(yesterdayRow.computedAt).getTime() < endOfYesterday\n ) {\n await this.materializeDate(yesterday, { force: true })\n }\n } else {\n await this.materializeDate(yesterday, { force: true })\n }\n\n const duration = Date.now() - start\n dbLogger.info({ duration }, 'report stats materialization completed')\n } catch (err) {\n dbLogger.error({ err }, 'report stats materialization errored')\n }\n }\n\n /**\n * Compute stats for a specific date range. Used by the refreshStats endpoint.\n */\n async refreshDateRange(opts: {\n startDate: string\n endDate: string\n queueIds?: number[]\n }): Promise<void> {\n const start = new Date(opts.startDate)\n const end = new Date(opts.endDate)\n\n for (let d = new Date(start); d <= end; d.setUTCDate(d.getUTCDate() + 1)) {\n const dateStr = toDateString(d)\n if (opts.queueIds?.length) {\n // Recompute only specific queue groups for this date\n const batched = await this.computeBatchedStats(dateStr)\n const rows: UpsertRow[] = []\n for (const queueId of opts.queueIds) {\n const group: ReportStatGroup = {\n queueId,\n moderatorDid: null,\n reportTypes: null,\n }\n const stats = this.resolveGroupStats(group, batched)\n rows.push(this.buildUpsertRow(dateStr, group, stats))\n }\n await this.bulkUpsert(rows)\n } else {\n await this.materializeDate(dateStr, { force: true })\n }\n }\n }\n\n /** Compute and write all groups for a single date. */\n private async materializeDate(\n date: string,\n opts?: { force?: boolean },\n ): Promise<void> {\n const groups = await this.enumerateGroups()\n const batched = await this.computeBatchedStats(date)\n const today = toDateString(new Date())\n const isToday = date === today\n\n // Batch the cache check so we don't issue one SELECT per group.\n const existingByKey = !opts?.force\n ? await this.fetchExistingStatsByKey(date)\n : null\n\n const rows: UpsertRow[] = []\n for (const group of groups) {\n try {\n if (existingByKey) {\n const cached = existingByKey.get(groupKey(group))\n if (cached) {\n // Historical dates: never recompute. Today: recompute if stale.\n if (!isToday) continue\n const age = Date.now() - new Date(cached.computedAt).getTime()\n if (age < REPORT_STAT_LIVE_TTL) continue\n }\n }\n const stats = this.resolveGroupStats(group, batched)\n rows.push(this.buildUpsertRow(date, group, stats))\n } catch (err) {\n dbLogger.error(\n { err, group, date },\n 'error preparing report stats group',\n )\n }\n }\n\n await this.bulkUpsert(rows)\n }\n\n /** Fetch all stat rows for a date, keyed by groupKey for O(1) lookup. */\n private async fetchExistingStatsByKey(\n date: string,\n ): Promise<Map<string, Selectable<ReportStat>>> {\n const existing = await this.db.db\n .selectFrom('report_stat')\n .selectAll()\n .where('date', '=', date)\n .execute()\n const map = new Map<string, Selectable<ReportStat>>()\n for (const row of existing) {\n map.set(\n groupKey({\n queueId: row.queueId,\n moderatorDid: row.moderatorDid,\n reportTypes: row.reportTypes,\n }),\n row,\n )\n }\n return map\n }\n\n /** List out the groups to compute stats for. */\n private async enumerateGroups(): Promise<ReportStatGroup[]> {\n const groups: ReportStatGroup[] = []\n\n const queues = await this.db.db\n .selectFrom('report_queue')\n .selectAll()\n .where('enabled', '=', true)\n .where('deletedAt', 'is', null)\n .execute()\n const members = await this.db.db\n .selectFrom('member')\n .select('did')\n .where('disabled', '=', false)\n .where('role', 'in', [\n 'tools.ozone.team.defs#roleAdmin',\n 'tools.ozone.team.defs#roleModerator',\n 'tools.ozone.team.defs#roleTriage',\n ])\n .execute()\n\n // aggregate\n groups.push({ queueId: null, moderatorDid: null, reportTypes: null })\n // per queue\n for (const queue of queues) {\n groups.push({ queueId: queue.id, moderatorDid: null, reportTypes: null })\n }\n // unqueued\n groups.push({ queueId: -1, moderatorDid: null, reportTypes: null })\n // per moderator\n for (const member of members) {\n groups.push({\n queueId: null,\n moderatorDid: member.did,\n reportTypes: null,\n })\n }\n // per report type group\n for (const groupTypes of Object.values(REPORT_TYPE_GROUPS)) {\n groups.push({\n queueId: null,\n moderatorDid: null,\n reportTypes: groupTypes,\n })\n }\n\n return groups\n }\n\n /**\n * Run batched GROUP BY queries for a calendar date.\n * Returns 5 result sets covering all group types.\n */\n private async computeBatchedStats(date: string): Promise<BatchedStats> {\n const dayStart = `${date}T00:00:00.000Z`\n const dayEnd = `${nextDate(date)}T00:00:00.000Z`\n\n const [queuePending, aggregatePending] = await Promise.all([\n // Pending count is a snapshot of all non-closed reports at time of computation\n this.db.db\n .selectFrom('report')\n .select(['queueId', sql<string>`count(*)`.as('count')])\n .where('status', '!=', 'closed')\n .where('queueId', 'is not', null)\n .groupBy('queueId')\n .execute(),\n // Aggregate pending (includes all reports, even un-routed)\n this.db.db\n .selectFrom('report')\n .select(sql<string>`count(*)`.as('count'))\n .where('status', '!=', 'closed')\n .executeTakeFirst(),\n ])\n\n const queueWindow = await this.db.db\n .selectFrom('report')\n .select([\n 'queueId',\n sql<string>`count(*)`.as('inboundCount'),\n sql<string>`count(*) filter (where \"status\" = 'closed' and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'actionedCount',\n ),\n sql<string>`count(*) filter (where \"status\" = 'escalated')`.as(\n 'escalatedCount',\n ),\n sql<string>`sum(extract(epoch from (\"closedAt\"::timestamp - \"createdAt\"::timestamp))) filter (where \"status\" = 'closed' and \"closedAt\" is not null and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'handlingTimeSum',\n ),\n sql<string>`count(*) filter (where \"status\" = 'closed' and \"closedAt\" is not null and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'handlingTimeCount',\n ),\n ])\n .where('createdAt', '>=', dayStart)\n .where('createdAt', '<', dayEnd)\n .where('queueId', 'is not', null)\n .groupBy('queueId')\n .execute()\n\n // Aggregate windowed (includes all reports)\n const aggregateWindow = await this.db.db\n .selectFrom('report')\n .select([\n sql<string>`count(*)`.as('inboundCount'),\n sql<string>`count(*) filter (where \"status\" = 'closed' and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'actionedCount',\n ),\n sql<string>`count(*) filter (where \"status\" = 'escalated')`.as(\n 'escalatedCount',\n ),\n sql<string>`sum(extract(epoch from (\"closedAt\"::timestamp - \"createdAt\"::timestamp))) filter (where \"status\" = 'closed' and \"closedAt\" is not null and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'handlingTimeSum',\n ),\n sql<string>`count(*) filter (where \"status\" = 'closed' and \"closedAt\" is not null and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'handlingTimeCount',\n ),\n ])\n .where('createdAt', '>=', dayStart)\n .where('createdAt', '<', dayEnd)\n .executeTakeFirst()\n\n const typePending = await this.db.db\n .selectFrom('report')\n .select(['reportType', sql<string>`count(*)`.as('count')])\n .where('status', '!=', 'closed')\n .groupBy('reportType')\n .execute()\n\n const typeWindow = await this.db.db\n .selectFrom('report')\n .select([\n 'reportType',\n sql<string>`count(*)`.as('inboundCount'),\n sql<string>`count(*) filter (where \"status\" = 'closed' and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'actionedCount',\n ),\n sql<string>`count(*) filter (where \"status\" = 'escalated')`.as(\n 'escalatedCount',\n ),\n sql<string>`sum(extract(epoch from (\"closedAt\"::timestamp - \"createdAt\"::timestamp))) filter (where \"status\" = 'closed' and \"closedAt\" is not null and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'handlingTimeSum',\n ),\n sql<string>`count(*) filter (where \"status\" = 'closed' and \"closedAt\" is not null and \"closedAt\" >= ${dayStart} and \"closedAt\" < ${dayEnd})`.as(\n 'handlingTimeCount',\n ),\n ])\n .where('createdAt', '>=', dayStart)\n .where('createdAt', '<', dayEnd)\n .groupBy('reportType')\n .execute()\n\n const moderator = await this.db.db\n .selectFrom('report as r')\n .innerJoin('moderator_assignment as ma', (join) =>\n join.onRef('ma.reportId', '=', 'r.id').on('ma.endAt', 'is', null),\n )\n .select([\n 'ma.did',\n sql<string>`count(*)`.as('inboundCount'),\n sql<string>`count(*) filter (where r.\"status\" = 'closed')`.as(\n 'actionedCount',\n ),\n sql<string>`sum(extract(epoch from (r.\"closedAt\"::timestamp - ma.\"startAt\"::timestamp))) filter (where r.\"status\" = 'closed' and r.\"closedAt\" is not null)`.as(\n 'handlingTimeSum',\n ),\n sql<string>`count(*) filter (where r.\"status\" = 'closed' and r.\"closedAt\" is not null)`.as(\n 'handlingTimeCount',\n ),\n ])\n .where('r.createdAt', '>=', dayStart)\n .where('r.createdAt', '<', dayEnd)\n .groupBy('ma.did')\n .execute()\n\n // Inject aggregate as a synthetic row with queueId=null so resolveQueueStats can find it\n const allQueuePending: QueueCountRow[] = [\n ...queuePending,\n { queueId: null, count: aggregatePending?.count ?? '0' },\n ]\n const allQueueWindow: QueueWindowRow[] = aggregateWindow\n ? [\n ...queueWindow,\n {\n queueId: null,\n inboundCount: aggregateWindow.inboundCount,\n actionedCount: aggregateWindow.actionedCount,\n escalatedCount: aggregateWindow.escalatedCount,\n handlingTimeSum: aggregateWindow.handlingTimeSum,\n handlingTimeCount: aggregateWindow.handlingTimeCount,\n },\n ]\n : queueWindow\n\n return {\n queuePending: allQueuePending,\n queueWindow: allQueueWindow,\n typePending,\n typeWindow,\n moderator,\n }\n }\n\n /** Resolve a single group's stats from batched query results (pure in-memory). */\n private resolveGroupStats(\n group: ReportStatGroup,\n batched: BatchedStats,\n ): ReportStatistics {\n if (group.moderatorDid) {\n return this.resolveModeratorStats(group.moderatorDid, batched.moderator)\n }\n if (group.reportTypes !== null) {\n return this.resolveReportTypeStats(group.reportTypes, batched)\n }\n return this.resolveQueueStats(group.queueId, batched)\n }\n\n private resolveQueueStats(\n queueId: number | null,\n batched: BatchedStats,\n ): AggregateStatistics | QueueStatistics {\n // queueId=null is the synthetic aggregate row\n const pending = batched.queuePending.find((r) => r.queueId === queueId)\n const window = batched.queueWindow.find((r) => r.queueId === queueId)\n\n const pendingCount = num(pending?.count)\n const inboundCount = num(window?.inboundCount)\n const actionedCount = num(window?.actionedCount)\n const escalatedCount = num(window?.escalatedCount)\n const handlingTimeSum = Number(window?.handlingTimeSum ?? 0)\n const handlingTimeCount = num(window?.handlingTimeCount)\n const actionRate =\n inboundCount > 0 ? Math.round((actionedCount / inboundCount) * 100) : 0\n const avgHandlingTimeSec =\n handlingTimeCount > 0\n ? Math.round(handlingTimeSum / handlingTimeCount)\n : undefined\n\n return {\n inboundCount,\n pendingCount,\n actionedCount,\n escalatedCount,\n actionRate,\n avgHandlingTimeSec,\n }\n }\n\n private resolveReportTypeStats(\n reportTypes: string[],\n batched: BatchedStats,\n ): ReportTypeStatistics {\n const types = new Set(reportTypes)\n\n const matchingPending = batched.typePending.filter((r) =>\n types.has(r.reportType),\n )\n const matchingWindow = batched.typeWindow.filter((r) =>\n types.has(r.reportType),\n )\n\n const pendingCount = sumNum(matchingPending, 'count')\n const inboundCount = sumNum(matchingWindow, 'inboundCount')\n const actionedCount = sumNum(matchingWindow, 'actionedCount')\n const escalatedCount = sumNum(matchingWindow, 'escalatedCount')\n const handlingTimeSum = matchingWindow.reduce(\n (sum, r) => sum + Number(r.handlingTimeSum ?? 0),\n 0,\n )\n const handlingTimeCount = sumNum(matchingWindow, 'handlingTimeCount')\n\n const actionRate =\n inboundCount > 0 ? Math.round((actionedCount / inboundCount) * 100) : 0\n const avgHandlingTimeSec =\n handlingTimeCount > 0\n ? Math.round(handlingTimeSum / handlingTimeCount)\n : undefined\n\n return {\n inboundCount,\n pendingCount,\n actionedCount,\n escalatedCount,\n actionRate,\n avgHandlingTimeSec,\n }\n }\n\n private resolveModeratorStats(\n moderatorDid: string,\n rows: ModeratorWindowRow[],\n ): ModeratorStatistics {\n const row = rows.find((r) => r.did === moderatorDid)\n\n const inboundCount = num(row?.inboundCount)\n const actionedCount = num(row?.actionedCount)\n const handlingTimeCount = num(row?.handlingTimeCount)\n const avgHandlingTimeSec =\n handlingTimeCount > 0 && row?.handlingTimeSum\n ? Math.round(Number(row.handlingTimeSum) / handlingTimeCount)\n : undefined\n\n return { inboundCount, actionedCount, avgHandlingTimeSec }\n }\n\n /** Build an upsert row from (date, group, stats). */\n private buildUpsertRow(\n date: string,\n group: ReportStatGroup,\n stats: ReportStatistics,\n ): UpsertRow {\n const pendingCount =\n 'pendingCount' in stats ? stats.pendingCount ?? null : null\n const escalatedCount =\n 'escalatedCount' in stats ? stats.escalatedCount ?? null : null\n const actionRate = 'actionRate' in stats ? stats.actionRate ?? null : null\n\n return {\n date,\n queueId: group.queueId,\n moderatorDid: group.moderatorDid,\n reportTypes: group.reportTypes,\n inboundCount: stats.inboundCount ?? null,\n pendingCount,\n actionedCount: stats.actionedCount ?? null,\n escalatedCount,\n actionRate,\n avgHandlingTimeSec: stats.avgHandlingTimeSec ?? null,\n computedAt: new Date().toISOString(),\n }\n }\n\n /**\n * Wraps a DELETE+INSERT for each row in a single transaction so we pay one\n * commit per cycle instead of one per group. NULL-aware WHERE clauses match\n * the existing PG <15 NULL semantics without needing a unique index.\n */\n private async bulkUpsert(rows: UpsertRow[]): Promise<void> {\n if (!rows.length) return\n\n await this.db.transaction(async (dbTxn) => {\n for (const r of rows) {\n let del = dbTxn.db.deleteFrom('report_stat').where('date', '=', r.date)\n del =\n r.queueId !== null\n ? del.where('queueId', '=', r.queueId)\n : del.where('queueId', 'is', null)\n del =\n r.moderatorDid !== null\n ? del.where('moderatorDid', '=', r.moderatorDid)\n : del.where('moderatorDid', 'is', null)\n del =\n r.reportTypes !== null\n ? del.where(\n sql<boolean>`\"reportTypes\"::jsonb = ${jsonb(r.reportTypes)}::jsonb`,\n )\n : del.where('reportTypes', 'is', null)\n await del.execute()\n\n await dbTxn.db\n .insertInto('report_stat')\n .values({\n date: r.date,\n queueId: r.queueId,\n moderatorDid: r.moderatorDid,\n reportTypes: r.reportTypes !== null ? jsonb(r.reportTypes) : null,\n inboundCount: r.inboundCount,\n pendingCount: r.pendingCount,\n actionedCount: r.actionedCount,\n escalatedCount: r.escalatedCount,\n actionRate: r.actionRate,\n avgHandlingTimeSec: r.avgHandlingTimeSec,\n computedAt: r.computedAt,\n })\n .execute()\n }\n })\n }\n\n // ─── Read methods ───\n\n /** Get a single stat row for a date + group. */\n private async getStatForDate(\n date: string,\n group: ReportStatGroup,\n ): Promise<Selectable<ReportStat> | undefined> {\n let qb = this.db.db\n .selectFrom('report_stat')\n .selectAll()\n .where('date', '=', date)\n if (group.queueId !== null) {\n qb = qb.where('queueId', '=', group.queueId)\n } else {\n qb = qb.where('queueId', 'is', null)\n }\n if (group.moderatorDid) {\n qb = qb.where('moderatorDid', '=', group.moderatorDid)\n } else {\n qb = qb.where('moderatorDid', 'is', null)\n }\n if (group.reportTypes !== null) {\n qb = qb.where(\n sql<boolean>`\"reportTypes\"::jsonb = ${jsonb(group.reportTypes)}::jsonb`,\n )\n } else {\n qb = qb.where('reportTypes', 'is', null)\n }\n return qb.executeTakeFirst()\n }\n\n /** Get today's live stats for a group. */\n async getLiveStats(\n group: ReportStatGroup,\n ): Promise<Selectable<ReportStat> | undefined> {\n const today = toDateString(new Date())\n return this.getStatForDate(today, group)\n }\n\n /** Get live stats for multiple queues in a single query. */\n async getLiveStatsForQueues(\n queueIds: number[],\n ): Promise<Map<number, Selectable<ReportStat>>> {\n if (!queueIds.length) return new Map()\n\n const today = toDateString(new Date())\n const rows = await this.db.db\n .selectFrom('report_stat')\n .selectAll()\n .where('date', '=', today)\n .where('queueId', 'in', queueIds)\n .where('moderatorDid', 'is', null)\n .where('reportTypes', 'is', null)\n .execute()\n\n const result = new Map<number, Selectable<ReportStat>>()\n for (const row of rows) {\n if (row.queueId !== null) {\n result.set(row.queueId, row)\n }\n }\n return result\n }\n\n /** Get historical stats for a date range, paginated. */\n async getHistoricalStats(opts: {\n group: ReportStatGroup\n startDate?: string\n endDate?: string\n limit: number\n cursor?: string\n }): Promise<{ stats: Selectable<ReportStat>[]; cursor?: string }> {\n const { group, startDate, endDate, limit } = opts\n const { queueId, moderatorDid, reportTypes } = group\n const { ref } = this.db.db.dynamic\n\n let qb = this.db.db.selectFrom('report_stat').selectAll()\n\n if (queueId !== null) {\n qb = qb.where('queueId', '=', queueId)\n } else {\n qb = qb.where('queueId', 'is', null)\n }\n if (moderatorDid) {\n qb = qb.where('moderatorDid', '=', moderatorDid)\n } else {\n qb = qb.where('moderatorDid', 'is', null)\n }\n if (reportTypes !== null) {\n qb = qb.where(\n sql<boolean>`\"reportTypes\"::jsonb = ${jsonb(reportTypes)}::jsonb`,\n )\n } else {\n qb = qb.where('reportTypes', 'is', null)\n }\n if (startDate) {\n qb = qb.where('date', '>=', toDateString(new Date(startDate)))\n }\n if (endDate) {\n qb = qb.where('date', '<=', toDateString(new Date(endDate)))\n }\n\n const keyset = new ComputedAtIdKeyset(ref('computedAt'), ref('id'))\n const paginatedBuilder = paginate(qb, {\n limit,\n cursor: opts.cursor,\n keyset,\n direction: 'desc',\n tryIndex: true,\n })\n\n const stats = await paginatedBuilder.execute()\n\n return { stats, cursor: keyset.packFromResult(stats) }\n }\n}\n\n// ─── Helpers ───\n\n/** Parse a pg bigint string to number, defaulting to 0. */\nfunction num(val: string | undefined | null): number {\n return val ? Number(val) : 0\n}\n\n/** Sum a numeric string field across rows. */\nfunction sumNum<T>(rows: T[], field: keyof T): number {\n return rows.reduce((sum, r) => sum + Number(r[field] ?? 0), 0)\n}\n\n/**\n * Stable cache-key for a stat group. Used to look up an existing row in the\n * batched cache map without issuing per-group SELECTs. Report types are\n * stringified in stored order, which matches REPORT_TYPE_GROUPS.\n */\nfunction groupKey(g: ReportStatGroup): string {\n return [\n g.queueId ?? 'null',\n g.moderatorDid ?? 'null',\n g.reportTypes ? JSON.stringify(g.reportTypes) : 'null',\n ].join('|')\n}\n\n/** Convert a Date to an ISO date string (YYYY-MM-DD). */\nfunction toDateString(d: Date): string {\n return d.toISOString().slice(0, 10)\n}\n\n/** Get the next calendar date string. */\nfunction nextDate(dateStr: string): string {\n const d = new Date(`${dateStr}T00:00:00.000Z`)\n d.setUTCDate(d.getUTCDate() + 1)\n return toDateString(d)\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/scheduled-action/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAEnC,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAA;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iDAAiD,CAAA;AAErF,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE7C,MAAM,MAAM,6BAA6B,GAAG,CAC1C,EAAE,EAAE,QAAQ,KACT,sBAAsB,CAAA;AAE3B,qBAAa,sBAAsB;IACd,EAAE,EAAE,QAAQ;IAA/B,YAAmB,EAAE,EAAE,QAAQ,EAAI;IAEnC,MAAM,CAAC,OAAO,SACA,QAAQ,4BACrB;IAED,qBAAqB,CACnB,MAAM,EAAE,UAAU,CAAC,eAAe,CAAC,GAClC,mBAAmB,CA0BrB;IAEK,cAAc,CAClB,gBAAgB,EAAE,gBAAgB,GACjC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAsDtC;IAEK,0BAA0B,CAC9B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC,CAU7C;IAEK,oBAAoB,CAAC,EACzB,MAAM,EACN,KAAU,EACV,SAAS,EACT,OAAO,EACP,QAAQ,EACR,QAAa,EACb,SAAkB,GACnB,EAAE;QACD,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,IAAI,CAAA;QAChB,OAAO,CAAC,EAAE,IAAI,CAAA;QACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;QACnB,QAAQ,EAAE,qBAAqB,EAAE,CAAA;QACjC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAC3B,GAAG,OAAO,CAAC;QACV,OAAO,EAAE,UAAU,CAAC,eAAe,CAAC,EAAE,CAAA;QACtC,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAC,CA6CD;IAEK,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QACxD,SAAS,EAAE,MAAM,EAAE,CAAA;QACnB,MAAM,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,SAAS,CAAC,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAC7D,CAAC,CAoCD;IAEK,0BAA0B,CAC9B,GAAG,EAAE,IAAI,GACR,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC,CAWxC;IAEK,oBAAoB,CACxB,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC,CAYf;IAEK,kBAAkB,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAYf;CACF"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/scheduled-action/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAEnC,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAA;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iDAAiD,CAAA;AAErF,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE7C,MAAM,MAAM,6BAA6B,GAAG,CAC1C,EAAE,EAAE,QAAQ,KACT,sBAAsB,CAAA;AAE3B,qBAAa,sBAAsB;IACd,EAAE,EAAE,QAAQ;IAA/B,YAAmB,EAAE,EAAE,QAAQ,EAAI;IAEnC,MAAM,CAAC,OAAO,SACA,QAAQ,4BACrB;IAED,qBAAqB,CACnB,MAAM,EAAE,UAAU,CAAC,eAAe,CAAC,GAClC,mBAAmB,CA0BrB;IAEK,cAAc,CAClB,gBAAgB,EAAE,gBAAgB,GACjC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAsDtC;IAEK,0BAA0B,CAC9B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC,CAU7C;IAEK,oBAAoB,CAAC,EACzB,MAAM,EACN,KAAU,EACV,SAAS,EACT,OAAO,EACP,QAAQ,EACR,QAAa,EACb,SAAkB,GACnB,EAAE;QACD,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,IAAI,CAAA;QAChB,OAAO,CAAC,EAAE,IAAI,CAAA;QACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;QACnB,QAAQ,EAAE,qBAAqB,EAAE,CAAA;QACjC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;KAC3B,GAAG,OAAO,CAAC;QACV,OAAO,EAAE,UAAU,CAAC,eAAe,CAAC,EAAE,CAAA;QACtC,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAC,CA8CD;IAEK,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QACxD,SAAS,EAAE,MAAM,EAAE,CAAA;QACnB,MAAM,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,SAAS,CAAC,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAC7D,CAAC,CAoCD;IAEK,0BAA0B,CAC9B,GAAG,EAAE,IAAI,GACR,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC,CAYxC;IAEK,oBAAoB,CACxB,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC,CAYf;IAEK,kBAAkB,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAYf;CACF"}
@@ -94,23 +94,20 @@ export class ScheduledActionService {
94
94
  query = query.where('did', 'in', subjects);
95
95
  }
96
96
  if (startTime) {
97
- query = query.where((qb) => {
98
- return qb
99
- .orWhere('executeAt', '>=', startTime.toISOString())
100
- .orWhere('executeAfter', '>=', startTime.toISOString());
101
- });
97
+ query = query.where((eb) => eb.or([
98
+ eb('executeAt', '>=', startTime.toISOString()),
99
+ eb('executeAfter', '>=', startTime.toISOString()),
100
+ ]));
102
101
  }
103
102
  if (endTime) {
104
- query = query.where((qb) => {
105
- return qb
106
- .orWhere('executeAt', '<=', endTime.toISOString())
107
- .orWhere('executeUntil', '<=', endTime.toISOString())
108
- .orWhere((sqb) => {
109
- return sqb
110
- .where('executeUntil', 'is', null)
111
- .where('executeAfter', '<=', endTime.toISOString());
112
- });
113
- });
103
+ query = query.where((eb) => eb.or([
104
+ eb('executeAt', '<=', endTime.toISOString()),
105
+ eb('executeUntil', '<=', endTime.toISOString()),
106
+ eb.and([
107
+ eb('executeUntil', 'is', null),
108
+ eb('executeAfter', '<=', endTime.toISOString()),
109
+ ]),
110
+ ]));
114
111
  }
115
112
  if (cursor) {
116
113
  query = query.where('id', direction === 'asc' ? '>' : '<', parseInt(cursor, 10));
@@ -162,11 +159,10 @@ export class ScheduledActionService {
162
159
  .selectFrom('scheduled_action')
163
160
  .selectAll()
164
161
  .where('status', '=', 'pending')
165
- .where((qb) => {
166
- return qb
167
- .orWhere('executeAfter', '<=', now.toISOString())
168
- .orWhere('executeAt', '<=', now.toISOString());
169
- })
162
+ .where((eb) => eb.or([
163
+ eb('executeAfter', '<=', now.toISOString()),
164
+ eb('executeAt', '<=', now.toISOString()),
165
+ ]))
170
166
  .execute();
171
167
  }
172
168
  async markActionAsExecuted(actionId, executionEventId) {
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/scheduled-action/service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAK1D,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAOvC,MAAM,OAAO,sBAAsB;IACjC,YAAmB,EAAY;kBAAZ,EAAE;IAAa,CAAC;IAEnC,MAAM,CAAC,OAAO;QACZ,OAAO,CAAC,EAAY,EAAE,EAAE,CAAC,IAAI,sBAAsB,CAAC,EAAE,CAAC,CAAA;IACzD,CAAC;IAED,qBAAqB,CACnB,MAAmC;QAEnC,OAAO;YACL,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,SAAS,EAAE,MAAM,CAAC,SAAiD;YACnE,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,SAAS,EAAE,MAAM,CAAC,SAAS;gBACzB,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;gBAC1C,CAAC,CAAC,SAAS;YACb,YAAY,EAAE,MAAM,CAAC,YAAY;gBAC/B,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE;gBAC7C,CAAC,CAAC,SAAS;YACb,YAAY,EAAE,MAAM,CAAC,YAAY;gBAC/B,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE;gBAC7C,CAAC,CAAC,SAAS;YACb,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;YAC7C,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;YACnD,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;YACnD,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,cAAc,EAAE,MAAM,CAAC,cAAc;gBACnC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,WAAW,EAAE;gBAC/C,CAAC,CAAC,SAAS;YACb,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,IAAI,SAAS;YACxD,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,IAAI,SAAS;SACvD,CAAA;IACH,CAAC;IAED,KAAK,CAAC,cAAc,CAClB,gBAAkC;QAElC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,gBAAgB,CAAA;QAE9D,8EAA8E;QAC9E,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,0BAA0B,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QACzE,IAAI,cAAc,EAAE,CAAC;YACnB,MAAM,IAAI,mBAAmB,CAC3B,4DAA4D,EAC5D,qBAAqB,CACtB,CAAA;QACH,CAAC;QAED,4EAA4E;QAC5E,IACE,cAAc,IAAI,gBAAgB;YAClC,gBAAgB,CAAC,YAAY;YAC7B,gBAAgB,CAAC,YAAY;YAC7B,gBAAgB,CAAC,YAAY,IAAI,gBAAgB,CAAC,YAAY,EAC9D,CAAC;YACD,MAAM,IAAI,mBAAmB,CAC3B,0CAA0C,EAC1C,mBAAmB,CACpB,CAAA;QACH,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QACpC,MAAM,kBAAkB,GACtB,CAAC,CAAC,WAAW,IAAI,gBAAgB,CAAC,IAAI,cAAc,IAAI,gBAAgB,CAAA;QAE1E,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aACrC,UAAU,CAAC,kBAAkB,CAAC;aAC9B,MAAM,CAAC;YACN,MAAM;YACN,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;YACpC,GAAG;YACH,SAAS,EAAE,kBAAkB;gBAC3B,CAAC,CAAC,IAAI;gBACN,CAAC,CAAC,gBAAgB,CAAC,SAAS,EAAE,WAAW,EAAE;YAC7C,YAAY,EAAE,kBAAkB;gBAC9B,CAAC,CAAC,gBAAgB,CAAC,YAAY,EAAE,WAAW,EAAE;gBAC9C,CAAC,CAAC,IAAI;YACR,YAAY,EAAE,kBAAkB;gBAC9B,CAAC,CAAC,gBAAgB,CAAC,YAAY,EAAE,WAAW,EAAE;gBAC9C,CAAC,CAAC,IAAI;YACR,kBAAkB;YAClB,SAAS;YACT,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;YACd,MAAM,EAAE,SAAS;SAClB,CAAC;aACD,YAAY,EAAE;aACd,uBAAuB,EAAE,CAAA;QAE5B,OAAO,eAAe,CAAA;IACxB,CAAC;IAED,KAAK,CAAC,0BAA0B,CAC9B,GAAW,EACX,MAA2B;QAE3B,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aACrC,UAAU,CAAC,kBAAkB,CAAC;aAC9B,SAAS,EAAE;aACX,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;aACtB,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,CAAC;aAC5B,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,CAAC;aAC/B,gBAAgB,EAAE,CAAA;QAErB,OAAO,eAAe,IAAI,IAAI,CAAA;IAChC,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,EACzB,MAAM,EACN,KAAK,GAAG,EAAE,EACV,SAAS,EACT,OAAO,EACP,QAAQ,EACR,QAAQ,GAAG,EAAE,EACb,SAAS,GAAG,MAAM,GASnB;QAIC,IAAI,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE;aACnB,UAAU,CAAC,kBAAkB,CAAC;aAC9B,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC;aAC/B,SAAS,EAAE,CAAA;QAEd,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAA;QAC5C,CAAC;QAED,IAAI,SAAS,EAAE,CAAC;YACd,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE;gBACzB,OAAO,EAAE;qBACN,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC;qBACnD,OAAO,CAAC,cAAc,EAAE,IAAI,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC,CAAA;YAC3D,CAAC,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE;gBACzB,OAAO,EAAE;qBACN,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;qBACjD,OAAO,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;qBACpD,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;oBACf,OAAO,GAAG;yBACP,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC;yBACjC,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;gBACvD,CAAC,CAAC,CAAA;YACN,CAAC,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,GAAG,KAAK,CAAC,KAAK,CACjB,IAAI,EACJ,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAC/B,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CACrB,CAAA;QACH,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAA;QAE3E,OAAO;YACL,OAAO;YACP,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE;SACvC,CAAA;IACH,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAC,QAAkB;QAI7C,MAAM,SAAS,GAAa,EAAE,CAAA;QAC9B,MAAM,MAAM,GAAyD,EAAE,CAAA;QAEvE,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;qBAC5B,WAAW,CAAC,kBAAkB,CAAC;qBAC/B,GAAG,CAAC;oBACH,MAAM,EAAE,WAAW;oBACnB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC;qBACD,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;qBACtB,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,CAAC;qBAC/B,gBAAgB,EAAE,CAAA;gBAErB,IAAI,MAAM,CAAC,cAAc,IAAI,MAAM,CAAC,cAAc,GAAG,CAAC,EAAE,CAAC;oBACvD,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;gBACrB,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,CAAC;wBACV,GAAG;wBACH,KAAK,EAAE,gDAAgD;wBACvD,SAAS,EAAE,kBAAkB;qBAC9B,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,mCAAmC,CAAC,CAAA;gBACtE,MAAM,CAAC,IAAI,CAAC;oBACV,GAAG;oBACH,KAAK,EAAE,eAAe;oBACtB,SAAS,EAAE,eAAe;iBAC3B,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;QAED,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAA;IAC9B,CAAC;IAED,KAAK,CAAC,0BAA0B,CAC9B,GAAS;QAET,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aACpB,UAAU,CAAC,kBAAkB,CAAC;aAC9B,SAAS,EAAE;aACX,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,CAAC;aAC/B,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE;YACZ,OAAO,EAAE;iBACN,OAAO,CAAC,cAAc,EAAE,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC;iBAChD,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAA;QAClD,CAAC,CAAC;aACD,OAAO,EAAE,CAAA;IACd,CAAC;IAED,KAAK,CAAC,oBAAoB,CACxB,QAAgB,EAChB,gBAAwB;QAExB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QACpC,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aACb,WAAW,CAAC,kBAAkB,CAAC;aAC/B,GAAG,CAAC;YACH,MAAM,EAAE,UAAU;YAClB,cAAc,EAAE,GAAG;YACnB,gBAAgB;YAChB,SAAS,EAAE,GAAG;SACf,CAAC;aACD,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,CAAC;aAC1B,OAAO,EAAE,CAAA;IACd,CAAC;IAED,KAAK,CAAC,kBAAkB,CACtB,QAAgB,EAChB,aAAqB;QAErB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QACpC,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aACb,WAAW,CAAC,kBAAkB,CAAC;aAC/B,GAAG,CAAC;YACH,MAAM,EAAE,QAAQ;YAChB,cAAc,EAAE,GAAG;YACnB,iBAAiB,EAAE,aAAa;YAChC,SAAS,EAAE,GAAG;SACf,CAAC;aACD,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,CAAC;aAC1B,OAAO,EAAE,CAAA;IACd,CAAC;CACF","sourcesContent":["import { Selectable } from 'kysely'\nimport { InvalidRequestError } from '@atproto/xrpc-server'\nimport { ScheduledActionStatus, ScheduledActionType } from '../api/util.js'\nimport { Database } from '../db/index.js'\nimport { ScheduledAction } from '../db/schema/scheduled-action.js'\nimport { ScheduledActionView } from '../lexicon/types/tools/ozone/moderation/defs.js'\nimport { dbLogger } from '../logger.js'\nimport { SchedulingParams } from './types.js'\n\nexport type ScheduledActionServiceCreator = (\n db: Database,\n) => ScheduledActionService\n\nexport class ScheduledActionService {\n constructor(public db: Database) {}\n\n static creator() {\n return (db: Database) => new ScheduledActionService(db)\n }\n\n formatScheduledAction(\n action: Selectable<ScheduledAction>,\n ): ScheduledActionView {\n return {\n id: action.id,\n action: action.action,\n eventData: action.eventData as { [x: string]: unknown } | undefined,\n did: action.did,\n executeAt: action.executeAt\n ? new Date(action.executeAt).toISOString()\n : undefined,\n executeAfter: action.executeAfter\n ? new Date(action.executeAfter).toISOString()\n : undefined,\n executeUntil: action.executeUntil\n ? new Date(action.executeUntil).toISOString()\n : undefined,\n randomizeExecution: action.randomizeExecution,\n createdBy: action.createdBy,\n createdAt: new Date(action.createdAt).toISOString(),\n updatedAt: new Date(action.updatedAt).toISOString(),\n status: action.status,\n lastExecutedAt: action.lastExecutedAt\n ? new Date(action.lastExecutedAt).toISOString()\n : undefined,\n lastFailureReason: action.lastFailureReason || undefined,\n executionEventId: action.executionEventId || undefined,\n }\n }\n\n async scheduleAction(\n schedulingParams: SchedulingParams,\n ): Promise<Selectable<ScheduledAction>> {\n const { action, eventData, did, createdBy } = schedulingParams\n\n // Only allow one pending action at a time for a given subject and action type\n const existingAction = await this.getPendingActionForSubject(did, action)\n if (existingAction) {\n throw new InvalidRequestError(\n 'A pending scheduled action already exists for this subject',\n 'ActionAlreadyExists',\n )\n }\n\n // When a time-range for action is specified, ensure that the range is valid\n if (\n 'executeAfter' in schedulingParams &&\n schedulingParams.executeAfter &&\n schedulingParams.executeUntil &&\n schedulingParams.executeAfter >= schedulingParams.executeUntil\n ) {\n throw new InvalidRequestError(\n 'executeAfter must be before executeUntil',\n 'InvalidScheduling',\n )\n }\n\n const now = new Date().toISOString()\n const randomizeExecution =\n !('executeAt' in schedulingParams) && 'executeAfter' in schedulingParams\n\n const scheduledAction = await this.db.db\n .insertInto('scheduled_action')\n .values({\n action,\n eventData: JSON.stringify(eventData),\n did,\n executeAt: randomizeExecution\n ? null\n : schedulingParams.executeAt?.toISOString(),\n executeAfter: randomizeExecution\n ? schedulingParams.executeAfter?.toISOString()\n : null,\n executeUntil: randomizeExecution\n ? schedulingParams.executeUntil?.toISOString()\n : null,\n randomizeExecution,\n createdBy,\n createdAt: now,\n updatedAt: now,\n status: 'pending',\n })\n .returningAll()\n .executeTakeFirstOrThrow()\n\n return scheduledAction\n }\n\n async getPendingActionForSubject(\n did: string,\n action: ScheduledActionType,\n ): Promise<Selectable<ScheduledAction> | null> {\n const scheduledAction = await this.db.db\n .selectFrom('scheduled_action')\n .selectAll()\n .where('did', '=', did)\n .where('action', '=', action)\n .where('status', '=', 'pending')\n .executeTakeFirst()\n\n return scheduledAction || null\n }\n\n async listScheduledActions({\n cursor,\n limit = 50,\n startTime,\n endTime,\n subjects,\n statuses = [],\n direction = 'desc',\n }: {\n cursor?: string\n limit?: number\n startTime?: Date\n endTime?: Date\n subjects?: string[]\n statuses: ScheduledActionStatus[]\n direction?: 'asc' | 'desc'\n }): Promise<{\n actions: Selectable<ScheduledAction>[]\n cursor?: string\n }> {\n let query = this.db.db\n .selectFrom('scheduled_action')\n .where('status', 'in', statuses)\n .selectAll()\n\n if (subjects && subjects.length > 0) {\n query = query.where('did', 'in', subjects)\n }\n\n if (startTime) {\n query = query.where((qb) => {\n return qb\n .orWhere('executeAt', '>=', startTime.toISOString())\n .orWhere('executeAfter', '>=', startTime.toISOString())\n })\n }\n\n if (endTime) {\n query = query.where((qb) => {\n return qb\n .orWhere('executeAt', '<=', endTime.toISOString())\n .orWhere('executeUntil', '<=', endTime.toISOString())\n .orWhere((sqb) => {\n return sqb\n .where('executeUntil', 'is', null)\n .where('executeAfter', '<=', endTime.toISOString())\n })\n })\n }\n\n if (cursor) {\n query = query.where(\n 'id',\n direction === 'asc' ? '>' : '<',\n parseInt(cursor, 10),\n )\n }\n\n const actions = await query.orderBy('id', direction).limit(limit).execute()\n\n return {\n actions,\n cursor: actions.at(-1)?.id?.toString(),\n }\n }\n\n async cancelScheduledActions(subjects: string[]): Promise<{\n succeeded: string[]\n failed: { did: string; error: string; errorCode?: string }[]\n }> {\n const succeeded: string[] = []\n const failed: { did: string; error: string; errorCode?: string }[] = []\n\n for (const did of subjects) {\n try {\n const result = await this.db.db\n .updateTable('scheduled_action')\n .set({\n status: 'cancelled',\n updatedAt: new Date().toISOString(),\n })\n .where('did', '=', did)\n .where('status', '=', 'pending')\n .executeTakeFirst()\n\n if (result.numUpdatedRows && result.numUpdatedRows > 0) {\n succeeded.push(did)\n } else {\n failed.push({\n did,\n error: 'No pending scheduled actions found for subject',\n errorCode: 'NoPendingActions',\n })\n }\n } catch (err) {\n dbLogger.error({ err, subjects }, 'Error cancelling scheduled action')\n failed.push({\n did,\n error: 'Unknown error',\n errorCode: 'DatabaseError',\n })\n }\n }\n\n return { succeeded, failed }\n }\n\n async getPendingActionsToExecute(\n now: Date,\n ): Promise<Selectable<ScheduledAction>[]> {\n return await this.db.db\n .selectFrom('scheduled_action')\n .selectAll()\n .where('status', '=', 'pending')\n .where((qb) => {\n return qb\n .orWhere('executeAfter', '<=', now.toISOString())\n .orWhere('executeAt', '<=', now.toISOString())\n })\n .execute()\n }\n\n async markActionAsExecuted(\n actionId: number,\n executionEventId: number,\n ): Promise<void> {\n const now = new Date().toISOString()\n await this.db.db\n .updateTable('scheduled_action')\n .set({\n status: 'executed',\n lastExecutedAt: now,\n executionEventId,\n updatedAt: now,\n })\n .where('id', '=', actionId)\n .execute()\n }\n\n async markActionAsFailed(\n actionId: number,\n failureReason: string,\n ): Promise<void> {\n const now = new Date().toISOString()\n await this.db.db\n .updateTable('scheduled_action')\n .set({\n status: 'failed',\n lastExecutedAt: now,\n lastFailureReason: failureReason,\n updatedAt: now,\n })\n .where('id', '=', actionId)\n .execute()\n }\n}\n"]}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/scheduled-action/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Selectable } from 'kysely'\nimport { InvalidRequestError } from '@atproto/xrpc-server'\nimport { ScheduledActionStatus, ScheduledActionType } from '../api/util.js'\nimport { Database } from '../db/index.js'\nimport { ScheduledAction } from '../db/schema/scheduled-action.js'\nimport { ScheduledActionView } from '../lexicon/types/tools/ozone/moderation/defs.js'\nimport { dbLogger } from '../logger.js'\nimport { SchedulingParams } from './types.js'\n\nexport type ScheduledActionServiceCreator = (\n db: Database,\n) => ScheduledActionService\n\nexport class ScheduledActionService {\n constructor(public db: Database) {}\n\n static creator() {\n return (db: Database) => new ScheduledActionService(db)\n }\n\n formatScheduledAction(\n action: Selectable<ScheduledAction>,\n ): ScheduledActionView {\n return {\n id: action.id,\n action: action.action,\n eventData: action.eventData as { [x: string]: unknown } | undefined,\n did: action.did,\n executeAt: action.executeAt\n ? new Date(action.executeAt).toISOString()\n : undefined,\n executeAfter: action.executeAfter\n ? new Date(action.executeAfter).toISOString()\n : undefined,\n executeUntil: action.executeUntil\n ? new Date(action.executeUntil).toISOString()\n : undefined,\n randomizeExecution: action.randomizeExecution,\n createdBy: action.createdBy,\n createdAt: new Date(action.createdAt).toISOString(),\n updatedAt: new Date(action.updatedAt).toISOString(),\n status: action.status,\n lastExecutedAt: action.lastExecutedAt\n ? new Date(action.lastExecutedAt).toISOString()\n : undefined,\n lastFailureReason: action.lastFailureReason || undefined,\n executionEventId: action.executionEventId || undefined,\n }\n }\n\n async scheduleAction(\n schedulingParams: SchedulingParams,\n ): Promise<Selectable<ScheduledAction>> {\n const { action, eventData, did, createdBy } = schedulingParams\n\n // Only allow one pending action at a time for a given subject and action type\n const existingAction = await this.getPendingActionForSubject(did, action)\n if (existingAction) {\n throw new InvalidRequestError(\n 'A pending scheduled action already exists for this subject',\n 'ActionAlreadyExists',\n )\n }\n\n // When a time-range for action is specified, ensure that the range is valid\n if (\n 'executeAfter' in schedulingParams &&\n schedulingParams.executeAfter &&\n schedulingParams.executeUntil &&\n schedulingParams.executeAfter >= schedulingParams.executeUntil\n ) {\n throw new InvalidRequestError(\n 'executeAfter must be before executeUntil',\n 'InvalidScheduling',\n )\n }\n\n const now = new Date().toISOString()\n const randomizeExecution =\n !('executeAt' in schedulingParams) && 'executeAfter' in schedulingParams\n\n const scheduledAction = await this.db.db\n .insertInto('scheduled_action')\n .values({\n action,\n eventData: JSON.stringify(eventData),\n did,\n executeAt: randomizeExecution\n ? null\n : schedulingParams.executeAt?.toISOString(),\n executeAfter: randomizeExecution\n ? schedulingParams.executeAfter?.toISOString()\n : null,\n executeUntil: randomizeExecution\n ? schedulingParams.executeUntil?.toISOString()\n : null,\n randomizeExecution,\n createdBy,\n createdAt: now,\n updatedAt: now,\n status: 'pending',\n })\n .returningAll()\n .executeTakeFirstOrThrow()\n\n return scheduledAction\n }\n\n async getPendingActionForSubject(\n did: string,\n action: ScheduledActionType,\n ): Promise<Selectable<ScheduledAction> | null> {\n const scheduledAction = await this.db.db\n .selectFrom('scheduled_action')\n .selectAll()\n .where('did', '=', did)\n .where('action', '=', action)\n .where('status', '=', 'pending')\n .executeTakeFirst()\n\n return scheduledAction || null\n }\n\n async listScheduledActions({\n cursor,\n limit = 50,\n startTime,\n endTime,\n subjects,\n statuses = [],\n direction = 'desc',\n }: {\n cursor?: string\n limit?: number\n startTime?: Date\n endTime?: Date\n subjects?: string[]\n statuses: ScheduledActionStatus[]\n direction?: 'asc' | 'desc'\n }): Promise<{\n actions: Selectable<ScheduledAction>[]\n cursor?: string\n }> {\n let query = this.db.db\n .selectFrom('scheduled_action')\n .where('status', 'in', statuses)\n .selectAll()\n\n if (subjects && subjects.length > 0) {\n query = query.where('did', 'in', subjects)\n }\n\n if (startTime) {\n query = query.where((eb) =>\n eb.or([\n eb('executeAt', '>=', startTime.toISOString()),\n eb('executeAfter', '>=', startTime.toISOString()),\n ]),\n )\n }\n\n if (endTime) {\n query = query.where((eb) =>\n eb.or([\n eb('executeAt', '<=', endTime.toISOString()),\n eb('executeUntil', '<=', endTime.toISOString()),\n eb.and([\n eb('executeUntil', 'is', null),\n eb('executeAfter', '<=', endTime.toISOString()),\n ]),\n ]),\n )\n }\n\n if (cursor) {\n query = query.where(\n 'id',\n direction === 'asc' ? '>' : '<',\n parseInt(cursor, 10),\n )\n }\n\n const actions = await query.orderBy('id', direction).limit(limit).execute()\n\n return {\n actions,\n cursor: actions.at(-1)?.id?.toString(),\n }\n }\n\n async cancelScheduledActions(subjects: string[]): Promise<{\n succeeded: string[]\n failed: { did: string; error: string; errorCode?: string }[]\n }> {\n const succeeded: string[] = []\n const failed: { did: string; error: string; errorCode?: string }[] = []\n\n for (const did of subjects) {\n try {\n const result = await this.db.db\n .updateTable('scheduled_action')\n .set({\n status: 'cancelled',\n updatedAt: new Date().toISOString(),\n })\n .where('did', '=', did)\n .where('status', '=', 'pending')\n .executeTakeFirst()\n\n if (result.numUpdatedRows && result.numUpdatedRows > 0) {\n succeeded.push(did)\n } else {\n failed.push({\n did,\n error: 'No pending scheduled actions found for subject',\n errorCode: 'NoPendingActions',\n })\n }\n } catch (err) {\n dbLogger.error({ err, subjects }, 'Error cancelling scheduled action')\n failed.push({\n did,\n error: 'Unknown error',\n errorCode: 'DatabaseError',\n })\n }\n }\n\n return { succeeded, failed }\n }\n\n async getPendingActionsToExecute(\n now: Date,\n ): Promise<Selectable<ScheduledAction>[]> {\n return await this.db.db\n .selectFrom('scheduled_action')\n .selectAll()\n .where('status', '=', 'pending')\n .where((eb) =>\n eb.or([\n eb('executeAfter', '<=', now.toISOString()),\n eb('executeAt', '<=', now.toISOString()),\n ]),\n )\n .execute()\n }\n\n async markActionAsExecuted(\n actionId: number,\n executionEventId: number,\n ): Promise<void> {\n const now = new Date().toISOString()\n await this.db.db\n .updateTable('scheduled_action')\n .set({\n status: 'executed',\n lastExecutedAt: now,\n executionEventId,\n updatedAt: now,\n })\n .where('id', '=', actionId)\n .execute()\n }\n\n async markActionAsFailed(\n actionId: number,\n failureReason: string,\n ): Promise<void> {\n const now = new Date().toISOString()\n await this.db.db\n .updateTable('scheduled_action')\n .set({\n status: 'failed',\n lastExecutedAt: now,\n lastFailureReason: failureReason,\n updatedAt: now,\n })\n .where('id', '=', actionId)\n .execute()\n }\n}\n"]}
@@ -7,7 +7,16 @@ export declare class SetService {
7
7
  db: Database;
8
8
  constructor(db: Database);
9
9
  static creator(): (db: Database) => SetService;
10
- buildQueryForSetWithSize(): import("kysely").QueryBuilderWithSelection<import("kysely/dist/esm/parser/table-parser.js").From<import("../db/schema/index.js").DatabaseSchemaType, "set_detail as s">, "s", {}, "s.createdAt" | "s.description" | "s.id" | "s.name" | "s.updatedAt" | ((eb: import("kysely").ExpressionBuilder<import("kysely/dist/esm/parser/table-parser.js").From<import("../db/schema/index.js").DatabaseSchemaType, "set_detail as s">, "s">) => import("kysely").AliasedQueryBuilder<import("kysely/dist/esm/parser/table-parser.js").From<import("kysely/dist/esm/parser/table-parser.js").From<import("../db/schema/index.js").DatabaseSchemaType, "set_detail as s">, "set_value">, import("kysely/dist/esm/parser/table-parser.js").FromTables<import("kysely/dist/esm/parser/table-parser.js").From<import("../db/schema/index.js").DatabaseSchemaType, "set_detail as s">, "s", "set_value">, import("kysely").Selection<import("kysely/dist/esm/parser/table-parser.js").From<import("kysely/dist/esm/parser/table-parser.js").From<import("../db/schema/index.js").DatabaseSchemaType, "set_detail as s">, "set_value">, import("kysely/dist/esm/parser/table-parser.js").FromTables<import("kysely/dist/esm/parser/table-parser.js").From<import("../db/schema/index.js").DatabaseSchemaType, "set_detail as s">, "s", "set_value">, (e: import("kysely").ExpressionBuilder<import("kysely/dist/esm/parser/table-parser.js").From<import("kysely/dist/esm/parser/table-parser.js").From<import("../db/schema/index.js").DatabaseSchemaType, "set_detail as s">, "set_value">, import("kysely/dist/esm/parser/table-parser.js").FromTables<import("kysely/dist/esm/parser/table-parser.js").From<import("../db/schema/index.js").DatabaseSchemaType, "set_detail as s">, "s", "set_value">>) => import("kysely").AliasedAggregateFunctionBuilder<import("kysely/dist/esm/parser/table-parser.js").From<import("kysely/dist/esm/parser/table-parser.js").From<import("../db/schema/index.js").DatabaseSchemaType, "set_detail as s">, "set_value">, import("kysely/dist/esm/parser/table-parser.js").FromTables<import("kysely/dist/esm/parser/table-parser.js").From<import("../db/schema/index.js").DatabaseSchemaType, "set_detail as s">, "s", "set_value">, number, "count">>, "setSize">)>;
10
+ buildQueryForSetWithSize(): import("kysely").SelectQueryBuilder<import("../db/schema/moderation_event.js").PartialDB & import("../db/schema/moderation_subject_status.js").PartialDB & import("../db/schema/report.js").PartialDB & import("../db/schema/report_activity.js").PartialDB & import("../db/schema/report_queue.js").PartialDB & import("../db/schema/label.js").PartialDB & import("../db/schema/signing_key.js").PartialDB & import("../db/schema/repo_push_event.js").PartialDB & import("../db/schema/record_push_event.js").PartialDB & import("../db/schema/blob_push_event.js").PartialDB & import("../db/schema/communication_template.js").PartialDB & import("../db/schema/ozone_set.js").PartialDB & import("../db/schema/member.js").PartialDB & import("../db/schema/setting.js").PartialDB & import("../db/schema/account_events_stats.js").PartialDB & import("../db/schema/record_events_stats.js").PartialDB & import("../db/schema/account_record_events_stats.js").PartialDB & import("../db/schema/account_record_status_stats.js").PartialDB & import("../db/schema/account_strike.js").PartialDB & import("../db/schema/verification.js").PartialDB & import("../db/schema/firehose_cursor.js").PartialDB & import("../db/schema/job_cursor.js").PartialDB & import("../db/schema/safelink.js").PartialDB & import("../db/schema/scheduled-action.js").PartialDB & import("../db/schema/moderator_assignment.js").PartialDB & import("../db/schema/report_stat.js").PartialDB & import("../db/schema/expiring_tag.js").PartialDB & {
11
+ s: SetDetail;
12
+ }, "s", {
13
+ createdAt: Date;
14
+ description: string | null;
15
+ id: number;
16
+ name: string;
17
+ setSize: number;
18
+ updatedAt: Date;
19
+ }>;
11
20
  query({ limit, cursor, namePrefix, sortBy, sortDirection, }: {
12
21
  limit: number;
13
22
  cursor?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/set/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,0CAA0C,CAAA;AAElE,MAAM,MAAM,iBAAiB,GAAG,CAAC,EAAE,EAAE,QAAQ,KAAK,UAAU,CAAA;AAE5D,qBAAa,UAAU;IACF,EAAE,EAAE,QAAQ;IAA/B,YAAmB,EAAE,EAAE,QAAQ,EAAI;IAEnC,MAAM,CAAC,OAAO,SACA,QAAQ,gBACrB;IAED,wBAAwB,oqEAcvB;IAEK,KAAK,CAAC,EACV,KAAK,EACL,MAAM,EACN,UAAU,EACV,MAAM,EACN,aAAa,GACd,EAAE;QACD,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,WAAW,CAAA;QAC1C,aAAa,EAAE,KAAK,GAAG,MAAM,CAAA;KAC9B,GAAG,OAAO,CAAC;QACV,IAAI,EAAE,UAAU,CAAC,SAAS,GAAG;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,EAAE,CAAA;QACnD,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAC,CAgCD;IAEK,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC,CAOxE;IAEK,iBAAiB,CACrB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,CAAC,SAAS,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,SAAS,CAAC,CAIlE;IAEK,gBAAgB,CAAC,EACrB,IAAI,EACJ,KAAK,EACL,MAAM,GACP,EAAE;QACD,IAAI,EAAE,MAAM,CAAA;QACZ,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,GAAG,OAAO,CACP;QACE,GAAG,EAAE,UAAU,CAAC,SAAS,GAAG;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;QAChD,MAAM,EAAE,MAAM,EAAE,CAAA;QAChB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,GACD,SAAS,CACZ,CAyBA;IACK,MAAM,CAAC,EACX,IAAI,EACJ,WAAW,GACZ,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBzD;IAEK,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB9D;IAEK,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBjE;IAEK,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK5C;IAED,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAQ9D;CACF"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/set/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,UAAU,EAAE,MAAM,QAAQ,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,0CAA0C,CAAA;AAElE,MAAM,MAAM,iBAAiB,GAAG,CAAC,EAAE,EAAE,QAAQ,KAAK,UAAU,CAAA;AAE5D,qBAAa,UAAU;IACF,EAAE,EAAE,QAAQ;IAA/B,YAAmB,EAAE,EAAE,QAAQ,EAAI;IAEnC,MAAM,CAAC,OAAO,SACA,QAAQ,gBACrB;IAED,wBAAwB;;;;;;;;;OAiBvB;IAEK,KAAK,CAAC,EACV,KAAK,EACL,MAAM,EACN,UAAU,EACV,MAAM,EACN,aAAa,GACd,EAAE;QACD,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,WAAW,CAAA;QAC1C,aAAa,EAAE,KAAK,GAAG,MAAM,CAAA;KAC9B,GAAG,OAAO,CAAC;QACV,IAAI,EAAE,UAAU,CAAC,SAAS,GAAG;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,EAAE,CAAA;QACnD,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAC,CAgCD;IAEK,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC,CAOxE;IAEK,iBAAiB,CACrB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,CAAC,SAAS,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,SAAS,CAAC,CAIlE;IAEK,gBAAgB,CAAC,EACrB,IAAI,EACJ,KAAK,EACL,MAAM,GACP,EAAE;QACD,IAAI,EAAE,MAAM,CAAA;QACZ,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,GAAG,OAAO,CACP;QACE,GAAG,EAAE,UAAU,CAAC,SAAS,GAAG;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;QAChD,MAAM,EAAE,MAAM,EAAE,CAAA;QAChB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,GACD,SAAS,CACZ,CAyBA;IACK,MAAM,CAAC,EACX,IAAI,EACJ,WAAW,GACZ,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBzD;IAEK,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB9D;IAEK,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBjE;IAEK,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK5C;IAED,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAQ9D;CACF"}
@@ -7,7 +7,9 @@ export class SetService {
7
7
  return (db) => new SetService(db);
8
8
  }
9
9
  buildQueryForSetWithSize() {
10
- return this.db.db.selectFrom('set_detail as s').select([
10
+ return this.db.db
11
+ .selectFrom('set_detail as s')
12
+ .select([
11
13
  's.id',
12
14
  's.name',
13
15
  's.description',
@@ -18,7 +20,8 @@ export class SetService {
18
20
  .select((e) => e.fn.count('setId').as('count'))
19
21
  .whereRef('setId', '=', 's.id')
20
22
  .as('setSize'),
21
- ]);
23
+ ])
24
+ .$narrowType();
22
25
  }
23
26
  async query({ limit, cursor, namePrefix, sortBy, sortDirection, }) {
24
27
  let qb = this.buildQueryForSetWithSize().limit(limit);
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/set/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Selectable } from 'kysely'\nimport { Database } from '../db/index.js'\nimport { TimeIdKeyset, paginate } from '../db/pagination.js'\nimport { SetDetail } from '../db/schema/ozone_set.js'\nimport { SetView } from '../lexicon/types/tools/ozone/set/defs.js'\n\nexport type SetServiceCreator = (db: Database) => SetService\n\nexport class SetService {\n constructor(public db: Database) {}\n\n static creator() {\n return (db: Database) => new SetService(db)\n }\n\n buildQueryForSetWithSize() {\n return this.db.db.selectFrom('set_detail as s').select([\n 's.id',\n 's.name',\n 's.description',\n 's.createdAt',\n 's.updatedAt',\n (eb) =>\n eb\n .selectFrom('set_value')\n .select((e) => e.fn.count<number>('setId').as('count'))\n .whereRef('setId', '=', 's.id')\n .as('setSize'),\n ])\n }\n\n async query({\n limit,\n cursor,\n namePrefix,\n sortBy,\n sortDirection,\n }: {\n limit: number\n cursor?: string\n namePrefix?: string\n sortBy: 'name' | 'createdAt' | 'updatedAt'\n sortDirection: 'asc' | 'desc'\n }): Promise<{\n sets: Selectable<SetDetail & { setSize: number }>[]\n cursor?: string\n }> {\n let qb = this.buildQueryForSetWithSize().limit(limit)\n\n if (namePrefix) {\n qb = qb.where('s.name', 'like', `${namePrefix}%`)\n }\n\n if (cursor) {\n if (sortBy === 'name') {\n qb = qb.where('s.name', sortDirection === 'asc' ? '>' : '<', cursor)\n } else {\n qb = qb.where(\n `s.${sortBy}`,\n sortDirection === 'asc' ? '>' : '<',\n new Date(cursor),\n )\n }\n }\n\n qb = qb.orderBy(`s.${sortBy}`, sortDirection)\n\n const sets = await qb.execute()\n const lastItem = sets.at(-1)\n\n return {\n sets,\n cursor: lastItem\n ? sortBy === 'name'\n ? lastItem?.name\n : lastItem?.[sortBy].toISOString()\n : undefined,\n }\n }\n\n async getByName(name: string): Promise<Selectable<SetDetail> | undefined> {\n const query = this.db.db\n .selectFrom('set_detail')\n .selectAll()\n .where('name', '=', name)\n\n return await query.executeTakeFirst()\n }\n\n async getByNameWithSize(\n name: string,\n ): Promise<Selectable<SetDetail & { setSize: number }> | undefined> {\n return await this.buildQueryForSetWithSize()\n .where('s.name', '=', name)\n .executeTakeFirst()\n }\n\n async getSetWithValues({\n name,\n limit,\n cursor,\n }: {\n name: string\n limit: number\n cursor?: string\n }): Promise<\n | {\n set: Selectable<SetDetail & { setSize: number }>\n values: string[]\n cursor?: string\n }\n | undefined\n > {\n const set = await this.getByNameWithSize(name)\n if (!set) return undefined\n\n const { ref } = this.db.db.dynamic\n const qb = this.db.db\n .selectFrom('set_value')\n .selectAll()\n .where('setId', '=', set.id)\n\n const keyset = new TimeIdKeyset(ref(`createdAt`), ref('id'))\n const paginatedBuilder = paginate(qb, {\n limit,\n cursor,\n keyset,\n direction: 'asc',\n })\n\n const result = await paginatedBuilder.execute()\n\n return {\n set,\n values: result.map((v) => v.value),\n cursor: keyset.packFromResult(result),\n }\n }\n async upsert({\n name,\n description,\n }: Pick<SetDetail, 'name' | 'description'>): Promise<void> {\n await this.db.db\n .insertInto('set_detail')\n .values({\n name,\n description,\n updatedAt: new Date(),\n })\n .onConflict((oc) => {\n // if description is provided as a string, even an empty one, update it\n // otherwise, just update the updatedAt timestamp\n return oc.column('name').doUpdateSet(\n typeof description === 'string'\n ? {\n description,\n updatedAt: new Date(),\n }\n : { updatedAt: new Date() },\n )\n })\n .execute()\n }\n\n async addValues(setId: number, values: string[]): Promise<void> {\n await this.db.transaction(async (txn) => {\n const now = new Date()\n const query = txn.db\n .insertInto('set_value')\n .values(\n values.map((value) => ({\n setId,\n value,\n createdAt: now,\n })),\n )\n .onConflict((oc) => oc.columns(['setId', 'value']).doNothing())\n\n await query.execute()\n\n // Update the set's updatedAt timestamp\n await txn.db\n .updateTable('set_detail')\n .set({ updatedAt: now })\n .where('id', '=', setId)\n .execute()\n })\n }\n\n async removeValues(setId: number, values: string[]): Promise<void> {\n if (values.length < 1) {\n return\n }\n await this.db.transaction(async (txn) => {\n const query = txn.db\n .deleteFrom('set_value')\n .where('setId', '=', setId)\n .where('value', 'in', values)\n\n await query.execute()\n\n // Update the set's updatedAt timestamp\n await txn.db\n .updateTable('set_detail')\n .set({ updatedAt: new Date() })\n .where('id', '=', setId)\n .execute()\n })\n }\n\n async removeSet(setId: number): Promise<void> {\n await this.db.transaction(async (txn) => {\n await txn.db.deleteFrom('set_value').where('setId', '=', setId).execute()\n await txn.db.deleteFrom('set_detail').where('id', '=', setId).execute()\n })\n }\n\n view(set: Selectable<SetDetail> & { setSize: number }): SetView {\n return {\n name: set.name,\n description: set.description || undefined,\n setSize: set.setSize,\n createdAt: set.createdAt.toISOString(),\n updatedAt: set.updatedAt.toISOString(),\n }\n }\n}\n"]}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/set/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { NotNull, Selectable } from 'kysely'\nimport { Database } from '../db/index.js'\nimport { TimeIdKeyset, paginate } from '../db/pagination.js'\nimport { SetDetail } from '../db/schema/ozone_set.js'\nimport { SetView } from '../lexicon/types/tools/ozone/set/defs.js'\n\nexport type SetServiceCreator = (db: Database) => SetService\n\nexport class SetService {\n constructor(public db: Database) {}\n\n static creator() {\n return (db: Database) => new SetService(db)\n }\n\n buildQueryForSetWithSize() {\n return this.db.db\n .selectFrom('set_detail as s')\n .select([\n 's.id',\n 's.name',\n 's.description',\n 's.createdAt',\n 's.updatedAt',\n (eb) =>\n eb\n .selectFrom('set_value')\n .select((e) => e.fn.count<number>('setId').as('count'))\n .whereRef('setId', '=', 's.id')\n .as('setSize'),\n ])\n .$narrowType<{ setSize: NotNull }>()\n }\n\n async query({\n limit,\n cursor,\n namePrefix,\n sortBy,\n sortDirection,\n }: {\n limit: number\n cursor?: string\n namePrefix?: string\n sortBy: 'name' | 'createdAt' | 'updatedAt'\n sortDirection: 'asc' | 'desc'\n }): Promise<{\n sets: Selectable<SetDetail & { setSize: number }>[]\n cursor?: string\n }> {\n let qb = this.buildQueryForSetWithSize().limit(limit)\n\n if (namePrefix) {\n qb = qb.where('s.name', 'like', `${namePrefix}%`)\n }\n\n if (cursor) {\n if (sortBy === 'name') {\n qb = qb.where('s.name', sortDirection === 'asc' ? '>' : '<', cursor)\n } else {\n qb = qb.where(\n `s.${sortBy}`,\n sortDirection === 'asc' ? '>' : '<',\n new Date(cursor),\n )\n }\n }\n\n qb = qb.orderBy(`s.${sortBy}`, sortDirection)\n\n const sets = await qb.execute()\n const lastItem = sets.at(-1)\n\n return {\n sets,\n cursor: lastItem\n ? sortBy === 'name'\n ? lastItem?.name\n : lastItem?.[sortBy].toISOString()\n : undefined,\n }\n }\n\n async getByName(name: string): Promise<Selectable<SetDetail> | undefined> {\n const query = this.db.db\n .selectFrom('set_detail')\n .selectAll()\n .where('name', '=', name)\n\n return await query.executeTakeFirst()\n }\n\n async getByNameWithSize(\n name: string,\n ): Promise<Selectable<SetDetail & { setSize: number }> | undefined> {\n return await this.buildQueryForSetWithSize()\n .where('s.name', '=', name)\n .executeTakeFirst()\n }\n\n async getSetWithValues({\n name,\n limit,\n cursor,\n }: {\n name: string\n limit: number\n cursor?: string\n }): Promise<\n | {\n set: Selectable<SetDetail & { setSize: number }>\n values: string[]\n cursor?: string\n }\n | undefined\n > {\n const set = await this.getByNameWithSize(name)\n if (!set) return undefined\n\n const { ref } = this.db.db.dynamic\n const qb = this.db.db\n .selectFrom('set_value')\n .selectAll()\n .where('setId', '=', set.id)\n\n const keyset = new TimeIdKeyset(ref(`createdAt`), ref('id'))\n const paginatedBuilder = paginate(qb, {\n limit,\n cursor,\n keyset,\n direction: 'asc',\n })\n\n const result = await paginatedBuilder.execute()\n\n return {\n set,\n values: result.map((v) => v.value),\n cursor: keyset.packFromResult(result),\n }\n }\n async upsert({\n name,\n description,\n }: Pick<SetDetail, 'name' | 'description'>): Promise<void> {\n await this.db.db\n .insertInto('set_detail')\n .values({\n name,\n description,\n updatedAt: new Date(),\n })\n .onConflict((oc) => {\n // if description is provided as a string, even an empty one, update it\n // otherwise, just update the updatedAt timestamp\n return oc.column('name').doUpdateSet(\n typeof description === 'string'\n ? {\n description,\n updatedAt: new Date(),\n }\n : { updatedAt: new Date() },\n )\n })\n .execute()\n }\n\n async addValues(setId: number, values: string[]): Promise<void> {\n await this.db.transaction(async (txn) => {\n const now = new Date()\n const query = txn.db\n .insertInto('set_value')\n .values(\n values.map((value) => ({\n setId,\n value,\n createdAt: now,\n })),\n )\n .onConflict((oc) => oc.columns(['setId', 'value']).doNothing())\n\n await query.execute()\n\n // Update the set's updatedAt timestamp\n await txn.db\n .updateTable('set_detail')\n .set({ updatedAt: now })\n .where('id', '=', setId)\n .execute()\n })\n }\n\n async removeValues(setId: number, values: string[]): Promise<void> {\n if (values.length < 1) {\n return\n }\n await this.db.transaction(async (txn) => {\n const query = txn.db\n .deleteFrom('set_value')\n .where('setId', '=', setId)\n .where('value', 'in', values)\n\n await query.execute()\n\n // Update the set's updatedAt timestamp\n await txn.db\n .updateTable('set_detail')\n .set({ updatedAt: new Date() })\n .where('id', '=', setId)\n .execute()\n })\n }\n\n async removeSet(setId: number): Promise<void> {\n await this.db.transaction(async (txn) => {\n await txn.db.deleteFrom('set_value').where('setId', '=', setId).execute()\n await txn.db.deleteFrom('set_detail').where('id', '=', setId).execute()\n })\n }\n\n view(set: Selectable<SetDetail> & { setSize: number }): SetView {\n return {\n name: set.name,\n description: set.description || undefined,\n setSize: set.setSize,\n createdAt: set.createdAt.toISOString(),\n updatedAt: set.updatedAt.toISOString(),\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/team/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/team/index.ts"],"names":[],"mappings":"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"}
@@ -31,9 +31,10 @@ export class TeamService {
31
31
  builder = builder.where('disabled', disabled ? 'is' : 'is not', true);
32
32
  }
33
33
  if (q) {
34
- builder = builder.where((qb) => qb
35
- .orWhere('handle', 'ilike', `%${q}%`)
36
- .orWhere('displayName', 'ilike', `%${q}%`));
34
+ builder = builder.where((eb) => eb.or([
35
+ eb('handle', 'ilike', `%${q}%`),
36
+ eb('displayName', 'ilike', `%${q}%`),
37
+ ]));
37
38
  }
38
39
  const members = await builder
39
40
  .limit(limit)
@@ -150,7 +151,7 @@ export class TeamService {
150
151
  .selectFrom('member')
151
152
  .select(['did'])
152
153
  .limit(25)
153
- .if(!!lastDid, (q) => q.where('did', '>', lastDid))
154
+ .$if(!!lastDid, (q) => q.where('did', '>', lastDid))
154
155
  .orderBy('did', 'asc')
155
156
  .execute();
156
157
  const dids = members.map((member) => member.did);