@atproto/ozone 0.2.2 → 0.2.4

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 (132) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/api/chat/index.d.ts.map +1 -1
  3. package/dist/api/chat/index.js +2 -0
  4. package/dist/api/chat/index.js.map +1 -1
  5. package/dist/api/health.d.ts.map +1 -1
  6. package/dist/api/moderation/util.d.ts.map +1 -1
  7. package/dist/api/util.d.ts +2 -2
  8. package/dist/api/util.d.ts.map +1 -1
  9. package/dist/api/well-known.d.ts.map +1 -1
  10. package/dist/assignment/index.d.ts.map +1 -1
  11. package/dist/assignment/index.js.map +1 -1
  12. package/dist/auth-verifier.d.ts.map +1 -1
  13. package/dist/background.d.ts.map +1 -1
  14. package/dist/background.js.map +1 -1
  15. package/dist/communication-service/template.d.ts.map +1 -1
  16. package/dist/communication-service/template.js.map +1 -1
  17. package/dist/communication-service/util.d.ts.map +1 -1
  18. package/dist/config/config.d.ts.map +1 -1
  19. package/dist/config/secrets.d.ts.map +1 -1
  20. package/dist/context.d.ts.map +1 -1
  21. package/dist/context.js.map +1 -1
  22. package/dist/daemon/blob-diverter.d.ts.map +1 -1
  23. package/dist/daemon/blob-diverter.js.map +1 -1
  24. package/dist/daemon/context.d.ts.map +1 -1
  25. package/dist/daemon/context.js.map +1 -1
  26. package/dist/daemon/event-pusher.d.ts +1 -1
  27. package/dist/daemon/event-pusher.d.ts.map +1 -1
  28. package/dist/daemon/event-reverser.d.ts.map +1 -1
  29. package/dist/daemon/index.d.ts.map +1 -1
  30. package/dist/daemon/index.js.map +1 -1
  31. package/dist/daemon/materialized-view-refresher.d.ts.map +1 -1
  32. package/dist/daemon/queue-router.d.ts.map +1 -1
  33. package/dist/daemon/scheduled-action-processor.d.ts.map +1 -1
  34. package/dist/daemon/stats-computer.d.ts.map +1 -1
  35. package/dist/daemon/strike-expiry-processor.d.ts.map +1 -1
  36. package/dist/daemon/team-profile-synchronizer.d.ts.map +1 -1
  37. package/dist/daemon/verification-listener.d.ts.map +1 -1
  38. package/dist/db/index.d.ts.map +1 -1
  39. package/dist/db/migrations/provider.d.ts.map +1 -1
  40. package/dist/db/migrations/provider.js.map +1 -1
  41. package/dist/db/pagination.d.ts +1 -1
  42. package/dist/db/pagination.d.ts.map +1 -1
  43. package/dist/db/pagination.js.map +1 -1
  44. package/dist/db/schema/index.d.ts.map +1 -1
  45. package/dist/db/types.d.ts.map +1 -1
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/jetstream/service.d.ts.map +1 -1
  48. package/dist/lexicon/index.d.ts +2 -0
  49. package/dist/lexicon/index.d.ts.map +1 -1
  50. package/dist/lexicon/index.js +4 -0
  51. package/dist/lexicon/index.js.map +1 -1
  52. package/dist/lexicon/lexicons.d.ts +17172 -17038
  53. package/dist/lexicon/lexicons.d.ts.map +1 -1
  54. package/dist/lexicon/lexicons.js +77 -1
  55. package/dist/lexicon/lexicons.js.map +1 -1
  56. package/dist/lexicon/types/chat/bsky/convo/defs.d.ts +13 -0
  57. package/dist/lexicon/types/chat/bsky/convo/defs.d.ts.map +1 -1
  58. package/dist/lexicon/types/chat/bsky/convo/defs.js +7 -0
  59. package/dist/lexicon/types/chat/bsky/convo/defs.js.map +1 -1
  60. package/dist/lexicon/types/chat/bsky/convo/getUnreadCounts.d.ts +25 -0
  61. package/dist/lexicon/types/chat/bsky/convo/getUnreadCounts.d.ts.map +1 -0
  62. package/dist/lexicon/types/chat/bsky/convo/getUnreadCounts.js +5 -0
  63. package/dist/lexicon/types/chat/bsky/convo/getUnreadCounts.js.map +1 -0
  64. package/dist/lexicon/types/chat/bsky/convo/sendMessage.d.ts +1 -1
  65. package/dist/lexicon/types/chat/bsky/convo/sendMessage.d.ts.map +1 -1
  66. package/dist/lexicon/types/chat/bsky/convo/sendMessage.js.map +1 -1
  67. package/dist/lexicon/types/chat/bsky/convo/sendMessageBatch.d.ts +1 -1
  68. package/dist/lexicon/types/chat/bsky/convo/sendMessageBatch.d.ts.map +1 -1
  69. package/dist/lexicon/types/chat/bsky/convo/sendMessageBatch.js.map +1 -1
  70. package/dist/lexicon/types/chat/bsky/convo/unlockConvo.d.ts +1 -1
  71. package/dist/lexicon/types/chat/bsky/convo/unlockConvo.d.ts.map +1 -1
  72. package/dist/lexicon/types/chat/bsky/convo/unlockConvo.js.map +1 -1
  73. package/dist/lexicon/types/chat/bsky/moderation/subscribeModEvents.d.ts +1 -1
  74. package/dist/lexicon/types/chat/bsky/moderation/subscribeModEvents.d.ts.map +1 -1
  75. package/dist/lexicon/types/chat/bsky/moderation/subscribeModEvents.js.map +1 -1
  76. package/dist/lexicon/util.d.ts.map +1 -1
  77. package/dist/mod-service/index.d.ts +38 -38
  78. package/dist/mod-service/index.d.ts.map +1 -1
  79. package/dist/mod-service/profile.d.ts.map +1 -1
  80. package/dist/mod-service/status.d.ts +80 -80
  81. package/dist/mod-service/status.d.ts.map +1 -1
  82. package/dist/mod-service/strike.d.ts.map +1 -1
  83. package/dist/mod-service/strike.js.map +1 -1
  84. package/dist/mod-service/subject.d.ts +4 -4
  85. package/dist/mod-service/subject.d.ts.map +1 -1
  86. package/dist/mod-service/util.d.ts +1 -1
  87. package/dist/mod-service/util.d.ts.map +1 -1
  88. package/dist/mod-service/views.d.ts.map +1 -1
  89. package/dist/mod-service/views.js.map +1 -1
  90. package/dist/queue/service.d.ts.map +1 -1
  91. package/dist/queue/service.js.map +1 -1
  92. package/dist/report/activity.d.ts +5 -5
  93. package/dist/report/activity.d.ts.map +1 -1
  94. package/dist/report/handle-report-update.d.ts.map +1 -1
  95. package/dist/report/handle-report-update.js.map +1 -1
  96. package/dist/report/stats.d.ts.map +1 -1
  97. package/dist/report/stats.js.map +1 -1
  98. package/dist/report/views.d.ts +2 -2
  99. package/dist/report/views.d.ts.map +1 -1
  100. package/dist/safelink/service.d.ts +3 -3
  101. package/dist/safelink/service.d.ts.map +1 -1
  102. package/dist/safelink/service.js.map +1 -1
  103. package/dist/scheduled-action/service.d.ts.map +1 -1
  104. package/dist/scheduled-action/service.js.map +1 -1
  105. package/dist/sequencer/outbox.d.ts.map +1 -1
  106. package/dist/sequencer/outbox.js.map +1 -1
  107. package/dist/sequencer/sequencer.d.ts.map +1 -1
  108. package/dist/sequencer/sequencer.js.map +1 -1
  109. package/dist/set/service.d.ts +1 -1
  110. package/dist/set/service.d.ts.map +1 -1
  111. package/dist/set/service.js.map +1 -1
  112. package/dist/setting/service.d.ts.map +1 -1
  113. package/dist/setting/service.js.map +1 -1
  114. package/dist/tag-service/content-tagger.d.ts.map +1 -1
  115. package/dist/tag-service/content-tagger.js.map +1 -1
  116. package/dist/tag-service/embed-tagger.d.ts.map +1 -1
  117. package/dist/tag-service/index.d.ts.map +1 -1
  118. package/dist/tag-service/index.js.map +1 -1
  119. package/dist/tag-service/language-tagger.d.ts.map +1 -1
  120. package/dist/tag-service/util.d.ts.map +1 -1
  121. package/dist/team/index.d.ts.map +1 -1
  122. package/dist/team/index.js.map +1 -1
  123. package/dist/util.d.ts.map +1 -1
  124. package/dist/verification/issuer.d.ts +1 -1
  125. package/dist/verification/issuer.d.ts.map +1 -1
  126. package/dist/verification/service.d.ts +5 -5
  127. package/dist/verification/service.d.ts.map +1 -1
  128. package/dist/verification/service.js.map +1 -1
  129. package/dist/verification/util.d.ts.map +1 -1
  130. package/package.json +13 -14
  131. package/src/api/chat/index.ts +2 -0
  132. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"handle-report-update.js","sourceRoot":"","sources":["../../src/report/handle-report-update.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure, synchronous state-transition logic for reports.\n *\n * Every code path that changes a report's status or creates a report activity\n * should call `handleReportUpdate` to determine the next status and the\n * activity record to insert. This keeps the state machine in one place and\n * decouples it from DB operations so it works for both single-row transactions\n * and bulk updates.\n */\n\n// ---------------------------------------------------------------------------\n// Error types — callers decide how to surface these (throw, skip, etc.)\n// ---------------------------------------------------------------------------\n\nexport class AlreadyInTargetState extends Error {\n constructor(\n public currentStatus: string,\n public targetStatus: string,\n ) {\n super(`Report is already in '${targetStatus}' status`)\n this.name = 'AlreadyInTargetState'\n }\n}\n\nexport class InvalidStateTransition extends Error {\n constructor(\n public fromStatus: string,\n public toStatus: string,\n ) {\n super(`Cannot transition report from '${fromStatus}' to '${toStatus}'`)\n this.name = 'InvalidStateTransition'\n }\n}\n\n// ---------------------------------------------------------------------------\n// State machine tables\n// ---------------------------------------------------------------------------\n\n/** Valid state transitions: key = fromState, value = allowed toStates */\nexport const VALID_TRANSITIONS: Record<string, string[]> = {\n open: ['closed', 'escalated', 'queued', 'assigned'],\n closed: ['open'],\n escalated: ['open', 'closed'],\n queued: ['assigned', 'open'],\n assigned: ['open', 'closed', 'escalated', 'queued'],\n}\n\n/** Activity types that map to a specific target status */\nconst ACTIVITY_TO_STATE: Record<string, string> = {\n queueActivity: 'queued',\n assignmentActivity: 'assigned',\n escalationActivity: 'escalated',\n closeActivity: 'closed',\n reopenActivity: 'open',\n}\n\n/** Activity types that are only valid from specific source states */\nconst ACTIVITY_VALID_FROM_STATES: Record<string, string[]> = {\n reopenActivity: ['closed'],\n}\n\n/** Moderation event types → target status (+ activity type) */\nconst EVENT_TYPE_MAP: Record<string, { status: string; activityType: string }> =\n {\n 'tools.ozone.moderation.defs#modEventAcknowledge': {\n status: 'closed',\n activityType: 'closeActivity',\n },\n 'tools.ozone.moderation.defs#modEventTakedown': {\n status: 'closed',\n activityType: 'closeActivity',\n },\n 'tools.ozone.moderation.defs#modEventLabel': {\n status: 'closed',\n activityType: 'closeActivity',\n },\n 'tools.ozone.moderation.defs#modEventComment': {\n status: 'closed',\n activityType: 'closeActivity',\n },\n 'tools.ozone.moderation.defs#modEventEscalate': {\n status: 'escalated',\n activityType: 'escalationActivity',\n },\n }\n\n// ---------------------------------------------------------------------------\n// Action types — the three ways a report's status can change\n// ---------------------------------------------------------------------------\n\nexport type ReportUpdateAction =\n | { type: 'activity'; activityType: string }\n | { type: 'event'; eventType: string }\n | { type: 'queue' }\n\n// ---------------------------------------------------------------------------\n// Result type\n// ---------------------------------------------------------------------------\n\nexport type ActivityRecord = {\n activityType: string\n previousStatus: string\n}\n\nexport type ReportUpdateResult = {\n nextStatus: string | null\n activity: ActivityRecord | null\n}\n\n// ---------------------------------------------------------------------------\n// Core function\n// ---------------------------------------------------------------------------\n\n/**\n * Determines the next status and activity record for a report update.\n *\n * @throws AlreadyInTargetState if the report is already in the target status\n * @throws InvalidStateTransition if the transition is not allowed\n * @returns nextStatus (null = no change) and activity (null = nothing to record)\n */\nexport function handleReportUpdate(\n currentStatus: string,\n action: ReportUpdateAction,\n): ReportUpdateResult {\n switch (action.type) {\n case 'activity':\n return handleActivityAction(currentStatus, action.activityType)\n case 'event':\n return handleEventAction(currentStatus, action.eventType)\n case 'queue':\n return handleQueueAction(currentStatus)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Action handlers\n// ---------------------------------------------------------------------------\n\nfunction handleActivityAction(\n currentStatus: string,\n activityType: string,\n): ReportUpdateResult {\n const toState = ACTIVITY_TO_STATE[activityType] ?? null\n\n // Note-type activities — no state change, but still produce an activity record\n if (toState === null) {\n return { nextStatus: null, activity: null }\n }\n\n // Check activity-specific source-state constraints\n const validFromStates = ACTIVITY_VALID_FROM_STATES[activityType]\n if (validFromStates && !validFromStates.includes(currentStatus)) {\n throw new InvalidStateTransition(currentStatus, toState)\n }\n\n validateTransition(currentStatus, toState)\n\n return {\n nextStatus: toState,\n activity: { activityType, previousStatus: currentStatus },\n }\n}\n\nfunction handleEventAction(\n currentStatus: string,\n eventType: string,\n): ReportUpdateResult {\n const mapping = EVENT_TYPE_MAP[eventType]\n if (!mapping) {\n // Event type doesn't affect report status\n return { nextStatus: null, activity: null }\n }\n\n validateTransition(currentStatus, mapping.status)\n\n return {\n nextStatus: mapping.status,\n activity: {\n activityType: mapping.activityType,\n previousStatus: currentStatus,\n },\n }\n}\n\nfunction handleQueueAction(currentStatus: string): ReportUpdateResult {\n // Queue routing only transitions open → queued\n if (currentStatus !== 'open') {\n return { nextStatus: null, activity: null }\n }\n\n return {\n nextStatus: 'queued',\n activity: { activityType: 'queueActivity', previousStatus: currentStatus },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Shared validation\n// ---------------------------------------------------------------------------\n\nfunction validateTransition(fromStatus: string, toStatus: string): void {\n if (fromStatus === toStatus) {\n throw new AlreadyInTargetState(fromStatus, toStatus)\n }\n const allowed = VALID_TRANSITIONS[fromStatus] ?? []\n if (!allowed.includes(toStatus)) {\n throw new InvalidStateTransition(fromStatus, toStatus)\n }\n}\n"]}
1
+ {"version":3,"file":"handle-report-update.js","sourceRoot":"","sources":["../../src/report/handle-report-update.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure, synchronous state-transition logic for reports.\n *\n * Every code path that changes a report's status or creates a report activity\n * should call `handleReportUpdate` to determine the next status and the\n * activity record to insert. This keeps the state machine in one place and\n * decouples it from DB operations so it works for both single-row transactions\n * and bulk updates.\n */\n\n// ---------------------------------------------------------------------------\n// Error types — callers decide how to surface these (throw, skip, etc.)\n// ---------------------------------------------------------------------------\n\nexport class AlreadyInTargetState extends Error {\n constructor(\n public currentStatus: string,\n public targetStatus: string,\n ) {\n super(`Report is already in '${targetStatus}' status`)\n this.name = 'AlreadyInTargetState'\n }\n}\n\nexport class InvalidStateTransition extends Error {\n constructor(\n public fromStatus: string,\n public toStatus: string,\n ) {\n super(`Cannot transition report from '${fromStatus}' to '${toStatus}'`)\n this.name = 'InvalidStateTransition'\n }\n}\n\n// ---------------------------------------------------------------------------\n// State machine tables\n// ---------------------------------------------------------------------------\n\n/** Valid state transitions: key = fromState, value = allowed toStates */\nexport const VALID_TRANSITIONS: Record<string, string[]> = {\n open: ['closed', 'escalated', 'queued', 'assigned'],\n closed: ['open'],\n escalated: ['open', 'closed'],\n queued: ['assigned', 'open'],\n assigned: ['open', 'closed', 'escalated', 'queued'],\n}\n\n/** Activity types that map to a specific target status */\nconst ACTIVITY_TO_STATE: Record<string, string> = {\n queueActivity: 'queued',\n assignmentActivity: 'assigned',\n escalationActivity: 'escalated',\n closeActivity: 'closed',\n reopenActivity: 'open',\n}\n\n/** Activity types that are only valid from specific source states */\nconst ACTIVITY_VALID_FROM_STATES: Record<string, string[]> = {\n reopenActivity: ['closed'],\n}\n\n/** Moderation event types → target status (+ activity type) */\nconst EVENT_TYPE_MAP: Record<string, { status: string; activityType: string }> =\n {\n 'tools.ozone.moderation.defs#modEventAcknowledge': {\n status: 'closed',\n activityType: 'closeActivity',\n },\n 'tools.ozone.moderation.defs#modEventTakedown': {\n status: 'closed',\n activityType: 'closeActivity',\n },\n 'tools.ozone.moderation.defs#modEventLabel': {\n status: 'closed',\n activityType: 'closeActivity',\n },\n 'tools.ozone.moderation.defs#modEventComment': {\n status: 'closed',\n activityType: 'closeActivity',\n },\n 'tools.ozone.moderation.defs#modEventEscalate': {\n status: 'escalated',\n activityType: 'escalationActivity',\n },\n }\n\n// ---------------------------------------------------------------------------\n// Action types — the three ways a report's status can change\n// ---------------------------------------------------------------------------\n\nexport type ReportUpdateAction =\n | { type: 'activity'; activityType: string }\n | { type: 'event'; eventType: string }\n | { type: 'queue' }\n\n// ---------------------------------------------------------------------------\n// Result type\n// ---------------------------------------------------------------------------\n\nexport type ActivityRecord = {\n activityType: string\n previousStatus: string\n}\n\nexport type ReportUpdateResult = {\n nextStatus: string | null\n activity: ActivityRecord | null\n}\n\n// ---------------------------------------------------------------------------\n// Core function\n// ---------------------------------------------------------------------------\n\n/**\n * Determines the next status and activity record for a report update.\n *\n * @throws AlreadyInTargetState if the report is already in the target status\n * @throws InvalidStateTransition if the transition is not allowed\n * @returns nextStatus (null = no change) and activity (null = nothing to record)\n */\nexport function handleReportUpdate(\n currentStatus: string,\n action: ReportUpdateAction,\n): ReportUpdateResult {\n switch (action.type) {\n case 'activity':\n return handleActivityAction(currentStatus, action.activityType)\n case 'event':\n return handleEventAction(currentStatus, action.eventType)\n case 'queue':\n return handleQueueAction(currentStatus)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Action handlers\n// ---------------------------------------------------------------------------\n\nfunction handleActivityAction(\n currentStatus: string,\n activityType: string,\n): ReportUpdateResult {\n const toState = ACTIVITY_TO_STATE[activityType] ?? null\n\n // Note-type activities — no state change, but still produce an activity record\n if (toState === null) {\n return { nextStatus: null, activity: null }\n }\n\n // Check activity-specific source-state constraints\n const validFromStates = ACTIVITY_VALID_FROM_STATES[activityType]\n if (validFromStates && !validFromStates.includes(currentStatus)) {\n throw new InvalidStateTransition(currentStatus, toState)\n }\n\n validateTransition(currentStatus, toState)\n\n return {\n nextStatus: toState,\n activity: { activityType, previousStatus: currentStatus },\n }\n}\n\nfunction handleEventAction(\n currentStatus: string,\n eventType: string,\n): ReportUpdateResult {\n const mapping = EVENT_TYPE_MAP[eventType]\n if (!mapping) {\n // Event type doesn't affect report status\n return { nextStatus: null, activity: null }\n }\n\n validateTransition(currentStatus, mapping.status)\n\n return {\n nextStatus: mapping.status,\n activity: {\n activityType: mapping.activityType,\n previousStatus: currentStatus,\n },\n }\n}\n\nfunction handleQueueAction(currentStatus: string): ReportUpdateResult {\n // Queue routing only transitions open → queued\n if (currentStatus !== 'open') {\n return { nextStatus: null, activity: null }\n }\n\n return {\n nextStatus: 'queued',\n activity: { activityType: 'queueActivity', previousStatus: currentStatus },\n }\n}\n\n// ---------------------------------------------------------------------------\n// Shared validation\n// ---------------------------------------------------------------------------\n\nfunction validateTransition(fromStatus: string, toStatus: string): void {\n if (fromStatus === toStatus) {\n throw new AlreadyInTargetState(fromStatus, toStatus)\n }\n const allowed = VALID_TRANSITIONS[fromStatus] ?? []\n if (!allowed.includes(toStatus)) {\n throw new InvalidStateTransition(fromStatus, toStatus)\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/report/stats.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/report/stats.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
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`\"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`\"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"]}
@@ -35,7 +35,6 @@ export declare function buildReportView(report: ReportWithEvent, hydrated: Hydra
35
35
  repo: ToolsOzoneModerationDefs.RepoViewDetail | undefined;
36
36
  record: RecordViewDetail | undefined;
37
37
  profile: {
38
- $type: "app.bsky.actor.defs#profileViewDetailed";
39
38
  did: string;
40
39
  handle: string;
41
40
  displayName?: string;
@@ -57,6 +56,7 @@ export declare function buildReportView(report: ReportWithEvent, hydrated: Hydra
57
56
  verification?: AppBskyActorDefs.VerificationState;
58
57
  status?: AppBskyActorDefs.StatusView;
59
58
  debug?: { [_ in string]: unknown; };
59
+ $type: 'app.bsky.actor.defs#profileViewDetailed';
60
60
  } | undefined;
61
61
  status: ToolsOzoneModerationDefs.SubjectStatusView | undefined;
62
62
  };
@@ -67,7 +67,6 @@ export declare function buildReportView(report: ReportWithEvent, hydrated: Hydra
67
67
  subject: string;
68
68
  repo: ToolsOzoneModerationDefs.RepoViewDetail | undefined;
69
69
  profile: {
70
- $type: "app.bsky.actor.defs#profileViewDetailed";
71
70
  did: string;
72
71
  handle: string;
73
72
  displayName?: string;
@@ -89,6 +88,7 @@ export declare function buildReportView(report: ReportWithEvent, hydrated: Hydra
89
88
  verification?: AppBskyActorDefs.VerificationState;
90
89
  status?: AppBskyActorDefs.StatusView;
91
90
  debug?: { [_ in string]: unknown; };
91
+ $type: 'app.bsky.actor.defs#profileViewDetailed';
92
92
  } | undefined;
93
93
  status: ToolsOzoneModerationDefs.SubjectStatusView | undefined;
94
94
  };
@@ -1 +1 @@
1
- {"version":3,"file":"views.d.ts","sourceRoot":"","sources":["../../src/report/views.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"views.d.ts","sourceRoot":"","sources":["../../src/report/views.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAEnC,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AACxD,OAAO,KAAK,gBAAgB,MAAM,yCAAyC,CAAA;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,4CAA4C,CAAA;AACxE,OAAO,EACL,gBAAgB,EAChB,QAAQ,EACT,MAAM,iDAAiD,CAAA;AACxD,OAAO,KAAK,wBAAwB,MAAM,iDAAiD,CAAA;AAC3F,OAAO,KAAK,mBAAmB,MAAM,4CAA4C,CAAA;AACjF,OAAO,KAAK,oBAAoB,MAAM,6CAA6C,CAAA;AACnF,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,2CAA2C,CAAA;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3C,KAAK,WAAW,GAAG;IACjB,WAAW,CACT,IAAI,EAAE,MAAM,EAAE,EACd,QAAQ,CAAC,EAAE,cAAc,GACxB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAA;IACjC,aAAa,CACX,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,EAC3B,QAAQ,CAAC,EAAE,cAAc,GACxB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAA;IACzC,WAAW,CACT,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,CAAA;CAC9D,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IACnC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC,CAAA;IAC5C,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;IACzC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAA;IAC3D,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAA;IAClD,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;CACrC,CAAA;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,eAAe,EAAE,EAC1B,KAAK,EAAE,WAAW,EAClB,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC,CAAC,EAC7E,SAAS,EAAE,CACT,QAAQ,EAAE,MAAM,EAAE,KACf,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC,EACxD,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,EACpE,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,cAAc,CAAC,CAuCzB;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,cAAc,EACxB,WAAW,EAAE,OAAO,EACpB,OAAO,CAAC,EAAE,wBAAwB,CAAC,YAAY,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAoClC,yCAAyC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAyBzC,yCAAyC;;;;;;;;;;;;;;;;;;EAyCzD;AAED,wBAAgB,cAAc,CAC5B,GAAG,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,GAC3B,mBAAmB,CAAC,UAAU,CAUhC;AAED,wBAAgB,aAAa,CAC3B,GAAG,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,GAC3B,oBAAoB,CAAC,SAAS,CAUhC;AAED,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,UAAU,CAAC,UAAU,CAAC,GAC1B,oBAAoB,CAAC,eAAe,CAWtC"}
@@ -32,15 +32,15 @@ export declare class SafelinkRuleService {
32
32
  comment?: string;
33
33
  }): Promise<Selectable<SafelinkEvent>>;
34
34
  getActiveRule(url: string, pattern: SafelinkPatternType): Promise<{
35
- id: number;
36
35
  action: SafelinkActionType;
37
36
  comment: string | null;
38
37
  createdAt: string;
39
38
  createdBy: string;
39
+ id: number;
40
+ pattern: SafelinkPatternType;
41
+ reason: SafelinkReasonType;
40
42
  updatedAt: string;
41
43
  url: string;
42
- reason: SafelinkReasonType;
43
- pattern: SafelinkPatternType;
44
44
  } | null>;
45
45
  getActiveRules({ cursor, limit, urls, patternType, actions, reason, createdBy, direction, }?: {
46
46
  cursor?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/safelink/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/safelink/service.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/safelink/service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAW1D,MAAM,OAAO,mBAAmB;IAC9B,YAAmB,EAAY;QAAZ,OAAE,GAAF,EAAE,CAAU;IAAG,CAAC;IAEnC,MAAM,CAAC,OAAO;QACZ,OAAO,CAAC,EAAY,EAAE,EAAE,CAAC,IAAI,mBAAmB,CAAC,EAAE,CAAC,CAAA;IACtD,CAAC;IAED,WAAW,CAAC,KAAgC;QAC1C,OAAO;YACL,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,SAAS,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;YAClD,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,SAAS;SACpC,CAAA;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EACZ,GAAG,EACH,OAAO,EACP,MAAM,EACN,MAAM,EACN,SAAS,EACT,OAAO,GAQR;QACC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QAC3D,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,IAAI,mBAAmB,CAC3B,2CAA2C,EAC3C,mBAAmB,CACpB,CAAA;QACH,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QACpC,MAAM,IAAI,GAAG;YACX,GAAG;YACH,OAAO;YACP,MAAM;YACN,MAAM;YACN,SAAS;YACT,OAAO,EAAE,OAAO,IAAI,IAAI;YACxB,SAAS,EAAE,GAAG;SACf,CAAA;QAED,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAC7C,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,EAAE;iBACvB,UAAU,CAAC,gBAAgB,CAAC;iBAC5B,MAAM,CAAC;gBACN,SAAS,EAAE,SAAS;gBACpB,GAAG,IAAI;aACR,CAAC;iBACD,YAAY,EAAE;iBACd,uBAAuB,EAAE,CAAA;YAE5B,MAAM,GAAG,CAAC,EAAE;iBACT,UAAU,CAAC,eAAe,CAAC;iBAC3B,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;iBACnC,OAAO,EAAE,CAAA;YAEZ,OAAO,KAAK,CAAA;QACd,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,EACf,GAAG,EACH,OAAO,EACP,MAAM,EACN,MAAM,EACN,SAAS,EACT,OAAO,GAQR;QACC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QAC3D,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,IAAI,mBAAmB,CAC3B,0CAA0C,EAC1C,cAAc,CACf,CAAA;QACH,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QACpC,MAAM,IAAI,GAAG;YACX,MAAM;YACN,MAAM;YACN,SAAS;YACT,OAAO,EAAE,OAAO,IAAI,IAAI;SACzB,CAAA;QAED,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAC7C,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,EAAE;iBACvB,UAAU,CAAC,gBAAgB,CAAC;iBAC5B,MAAM,CAAC;gBACN,SAAS,EAAE,GAAG;gBACd,GAAG,EAAE,YAAY,CAAC,GAAG;gBACrB,OAAO,EAAE,YAAY,CAAC,OAAO;gBAC7B,SAAS,EAAE,YAAY;gBACvB,GAAG,IAAI;aACR,CAAC;iBACD,YAAY,EAAE;iBACd,uBAAuB,EAAE,CAAA;YAE5B,MAAM,GAAG,CAAC,EAAE;iBACT,WAAW,CAAC,eAAe,CAAC;iBAC5B,GAAG,CAAC,IAAI,CAAC;iBACT,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,YAAY,CAAC,GAAG,CAAC;iBACnC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,YAAY,CAAC,OAAO,CAAC;iBAC3C,OAAO,EAAE,CAAA;YAEZ,OAAO,KAAK,CAAA;QACd,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,EACf,GAAG,EACH,OAAO,EACP,SAAS,EACT,OAAO,GAMR;QACC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QAC3D,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,IAAI,mBAAmB,CAC3B,0CAA0C,EAC1C,cAAc,CACf,CAAA;QACH,CAAC;QAED,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAC7C,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,EAAE;iBACvB,UAAU,CAAC,gBAAgB,CAAC;iBAC5B,MAAM,CAAC;gBACN,SAAS,EAAE,YAAY;gBACvB,GAAG;gBACH,OAAO;gBACP,MAAM,EAAE,YAAY,CAAC,MAAM;gBAC3B,MAAM,EAAE,YAAY,CAAC,MAAM;gBAC3B,SAAS;gBACT,OAAO,EAAE,OAAO,IAAI,IAAI;gBACxB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;iBACD,YAAY,EAAE;iBACd,uBAAuB,EAAE,CAAA;YAE5B,MAAM,GAAG,CAAC,EAAE;iBACT,UAAU,CAAC,eAAe,CAAC;iBAC3B,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;iBACtB,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC;iBAC9B,OAAO,EAAE,CAAA;YAEZ,OAAO,KAAK,CAAA;QACd,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,GAAW,EAAE,OAA4B;QAC3D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aAC1B,UAAU,CAAC,eAAe,CAAC;aAC3B,SAAS,EAAE;aACX,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;aACtB,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC;aAC9B,gBAAgB,EAAE,CAAA;QAErB,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,IAAI,CAAA;QACb,CAAC;QAED,OAAO,IAAI,CAAA;IACb,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,EACnB,MAAM,EACN,KAAK,GAAG,EAAE,EACV,IAAI,EACJ,WAAW,EACX,OAAO,EACP,MAAM,EACN,SAAS,EACT,SAAS,GAAG,MAAM,MAUhB,EAAE;QAIJ,IAAI,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,SAAS,EAAE,CAAA;QAE9D,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;QACxC,CAAC;QAED,IAAI,WAAW,EAAE,CAAC;YAChB,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,WAAW,CAAC,CAAA;QAClD,CAAC;QAED,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;QAC9C,CAAC;QAED,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,CAAC,CAAA;QAC5C,CAAC;QAED,IAAI,SAAS,EAAE,CAAC;YACd,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,SAAS,CAAC,CAAA;QAClD,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,KAAK,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAA;QAEzE,OAAO;YACL,KAAK;YACL,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE;SACrC,CAAA;IACH,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,EAChB,MAAM,EACN,KAAK,GAAG,EAAE,EACV,IAAI,EACJ,WAAW,EACX,SAAS,GAAG,MAAM,MAOhB,EAAE;QAIJ,IAAI,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC,SAAS,EAAE,CAAA;QAE/D,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;QACxC,CAAC;QAED,IAAI,WAAW,EAAE,CAAC;YAChB,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,WAAW,CAAC,CAAA;QAClD,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,MAAM,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAA;QAE1E,OAAO;YACL,MAAM;YACN,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE;SACtC,CAAA;IACH,CAAC;CACF","sourcesContent":["import { Selectable } from 'kysely'\nimport { ToolsOzoneSafelinkDefs } from '@atproto/api'\nimport { InvalidRequestError } from '@atproto/xrpc-server'\nimport {\n SafelinkActionType,\n SafelinkPatternType,\n SafelinkReasonType,\n} from '../api/util.js'\nimport { Database } from '../db/index.js'\nimport { SafelinkEvent, SafelinkRule } from '../db/schema/safelink.js'\n\nexport type SafelinkRuleServiceCreator = (db: Database) => SafelinkRuleService\n\nexport class SafelinkRuleService {\n constructor(public db: Database) {}\n\n static creator() {\n return (db: Database) => new SafelinkRuleService(db)\n }\n\n formatEvent(event: Selectable<SafelinkEvent>): ToolsOzoneSafelinkDefs.Event {\n return {\n id: event.id,\n eventType: event.eventType,\n url: event.url,\n pattern: event.pattern,\n action: event.action,\n reason: event.reason,\n createdBy: event.createdBy,\n createdAt: new Date(event.createdAt).toISOString(),\n comment: event.comment || undefined,\n }\n }\n\n async addRule({\n url,\n pattern,\n action,\n reason,\n createdBy,\n comment,\n }: {\n url: string\n pattern: SafelinkPatternType\n action: SafelinkActionType\n reason: SafelinkReasonType\n createdBy: string\n comment?: string\n }): Promise<Selectable<SafelinkEvent>> {\n const existingRule = await this.getActiveRule(url, pattern)\n if (existingRule) {\n throw new InvalidRequestError(\n 'A rule for this URL/domain already exists',\n 'RuleAlreadyExists',\n )\n }\n\n const now = new Date().toISOString()\n const rule = {\n url,\n pattern,\n action,\n reason,\n createdBy,\n comment: comment || null,\n createdAt: now,\n }\n\n return await this.db.transaction(async (txn) => {\n const event = await txn.db\n .insertInto('safelink_event')\n .values({\n eventType: 'addRule',\n ...rule,\n })\n .returningAll()\n .executeTakeFirstOrThrow()\n\n await txn.db\n .insertInto('safelink_rule')\n .values({ ...rule, updatedAt: now })\n .execute()\n\n return event\n })\n }\n\n async updateRule({\n url,\n pattern,\n action,\n reason,\n createdBy,\n comment,\n }: {\n url: string\n pattern: SafelinkPatternType\n action: SafelinkActionType\n reason: SafelinkReasonType\n createdBy: string\n comment?: string\n }): Promise<Selectable<SafelinkEvent>> {\n const existingRule = await this.getActiveRule(url, pattern)\n if (!existingRule) {\n throw new InvalidRequestError(\n 'No active rule found for this URL/domain',\n 'RuleNotFound',\n )\n }\n\n const now = new Date().toISOString()\n const rule = {\n action,\n reason,\n createdBy,\n comment: comment || null,\n }\n\n return await this.db.transaction(async (txn) => {\n const event = await txn.db\n .insertInto('safelink_event')\n .values({\n createdAt: now,\n url: existingRule.url,\n pattern: existingRule.pattern,\n eventType: 'updateRule',\n ...rule,\n })\n .returningAll()\n .executeTakeFirstOrThrow()\n\n await txn.db\n .updateTable('safelink_rule')\n .set(rule)\n .where('url', '=', existingRule.url)\n .where('pattern', '=', existingRule.pattern)\n .execute()\n\n return event\n })\n }\n\n async removeRule({\n url,\n pattern,\n createdBy,\n comment,\n }: {\n url: string\n pattern: SafelinkPatternType\n createdBy: string\n comment?: string\n }): Promise<Selectable<SafelinkEvent>> {\n const existingRule = await this.getActiveRule(url, pattern)\n if (!existingRule) {\n throw new InvalidRequestError(\n 'No active rule found for this URL/domain',\n 'RuleNotFound',\n )\n }\n\n return await this.db.transaction(async (txn) => {\n const event = await txn.db\n .insertInto('safelink_event')\n .values({\n eventType: 'removeRule',\n url,\n pattern,\n action: existingRule.action,\n reason: existingRule.reason,\n createdBy,\n comment: comment || null,\n createdAt: new Date().toISOString(),\n })\n .returningAll()\n .executeTakeFirstOrThrow()\n\n await txn.db\n .deleteFrom('safelink_rule')\n .where('url', '=', url)\n .where('pattern', '=', pattern)\n .execute()\n\n return event\n })\n }\n\n async getActiveRule(url: string, pattern: SafelinkPatternType) {\n const rule = await this.db.db\n .selectFrom('safelink_rule')\n .selectAll()\n .where('url', '=', url)\n .where('pattern', '=', pattern)\n .executeTakeFirst()\n\n if (!rule) {\n return null\n }\n\n return rule\n }\n\n async getActiveRules({\n cursor,\n limit = 50,\n urls,\n patternType,\n actions,\n reason,\n createdBy,\n direction = 'desc',\n }: {\n cursor?: string\n limit?: number\n urls?: string[]\n patternType?: SafelinkPatternType\n actions?: SafelinkActionType[]\n reason?: SafelinkReasonType\n createdBy?: string\n direction?: 'asc' | 'desc'\n } = {}): Promise<{\n rules: Selectable<SafelinkRule>[]\n cursor?: string\n }> {\n let query = this.db.db.selectFrom('safelink_rule').selectAll()\n\n if (urls && urls.length > 0) {\n query = query.where('url', 'in', urls)\n }\n\n if (patternType) {\n query = query.where('pattern', '=', patternType)\n }\n\n if (actions && actions.length > 0) {\n query = query.where('action', 'in', actions)\n }\n\n if (reason) {\n query = query.where('reason', '=', reason)\n }\n\n if (createdBy) {\n query = query.where('createdBy', '=', createdBy)\n }\n\n if (cursor) {\n query = query.where(\n 'id',\n direction === 'asc' ? '>' : '<',\n parseInt(cursor, 10),\n )\n }\n\n const rules = await query.orderBy('id', direction).limit(limit).execute()\n\n return {\n rules,\n cursor: rules.at(-1)?.id?.toString(),\n }\n }\n\n async queryEvents({\n cursor,\n limit = 50,\n urls,\n patternType,\n direction = 'desc',\n }: {\n cursor?: string\n limit?: number\n urls?: string[]\n patternType?: SafelinkPatternType\n direction?: 'asc' | 'desc'\n } = {}): Promise<{\n events: Selectable<SafelinkEvent>[]\n cursor?: string\n }> {\n let query = this.db.db.selectFrom('safelink_event').selectAll()\n\n if (urls && urls.length > 0) {\n query = query.where('url', 'in', urls)\n }\n\n if (patternType) {\n query = query.where('pattern', '=', patternType)\n }\n\n if (cursor) {\n query = query.where(\n 'id',\n direction === 'asc' ? '>' : '<',\n parseInt(cursor, 10),\n )\n }\n\n const events = await query.orderBy('id', direction).limit(limit).execute()\n\n return {\n events,\n cursor: events.at(-1)?.id?.toString(),\n }\n }\n}\n"]}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/safelink/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Selectable } from 'kysely'\nimport { ToolsOzoneSafelinkDefs } from '@atproto/api'\nimport { InvalidRequestError } from '@atproto/xrpc-server'\nimport {\n SafelinkActionType,\n SafelinkPatternType,\n SafelinkReasonType,\n} from '../api/util.js'\nimport { Database } from '../db/index.js'\nimport { SafelinkEvent, SafelinkRule } from '../db/schema/safelink.js'\n\nexport type SafelinkRuleServiceCreator = (db: Database) => SafelinkRuleService\n\nexport class SafelinkRuleService {\n constructor(public db: Database) {}\n\n static creator() {\n return (db: Database) => new SafelinkRuleService(db)\n }\n\n formatEvent(event: Selectable<SafelinkEvent>): ToolsOzoneSafelinkDefs.Event {\n return {\n id: event.id,\n eventType: event.eventType,\n url: event.url,\n pattern: event.pattern,\n action: event.action,\n reason: event.reason,\n createdBy: event.createdBy,\n createdAt: new Date(event.createdAt).toISOString(),\n comment: event.comment || undefined,\n }\n }\n\n async addRule({\n url,\n pattern,\n action,\n reason,\n createdBy,\n comment,\n }: {\n url: string\n pattern: SafelinkPatternType\n action: SafelinkActionType\n reason: SafelinkReasonType\n createdBy: string\n comment?: string\n }): Promise<Selectable<SafelinkEvent>> {\n const existingRule = await this.getActiveRule(url, pattern)\n if (existingRule) {\n throw new InvalidRequestError(\n 'A rule for this URL/domain already exists',\n 'RuleAlreadyExists',\n )\n }\n\n const now = new Date().toISOString()\n const rule = {\n url,\n pattern,\n action,\n reason,\n createdBy,\n comment: comment || null,\n createdAt: now,\n }\n\n return await this.db.transaction(async (txn) => {\n const event = await txn.db\n .insertInto('safelink_event')\n .values({\n eventType: 'addRule',\n ...rule,\n })\n .returningAll()\n .executeTakeFirstOrThrow()\n\n await txn.db\n .insertInto('safelink_rule')\n .values({ ...rule, updatedAt: now })\n .execute()\n\n return event\n })\n }\n\n async updateRule({\n url,\n pattern,\n action,\n reason,\n createdBy,\n comment,\n }: {\n url: string\n pattern: SafelinkPatternType\n action: SafelinkActionType\n reason: SafelinkReasonType\n createdBy: string\n comment?: string\n }): Promise<Selectable<SafelinkEvent>> {\n const existingRule = await this.getActiveRule(url, pattern)\n if (!existingRule) {\n throw new InvalidRequestError(\n 'No active rule found for this URL/domain',\n 'RuleNotFound',\n )\n }\n\n const now = new Date().toISOString()\n const rule = {\n action,\n reason,\n createdBy,\n comment: comment || null,\n }\n\n return await this.db.transaction(async (txn) => {\n const event = await txn.db\n .insertInto('safelink_event')\n .values({\n createdAt: now,\n url: existingRule.url,\n pattern: existingRule.pattern,\n eventType: 'updateRule',\n ...rule,\n })\n .returningAll()\n .executeTakeFirstOrThrow()\n\n await txn.db\n .updateTable('safelink_rule')\n .set(rule)\n .where('url', '=', existingRule.url)\n .where('pattern', '=', existingRule.pattern)\n .execute()\n\n return event\n })\n }\n\n async removeRule({\n url,\n pattern,\n createdBy,\n comment,\n }: {\n url: string\n pattern: SafelinkPatternType\n createdBy: string\n comment?: string\n }): Promise<Selectable<SafelinkEvent>> {\n const existingRule = await this.getActiveRule(url, pattern)\n if (!existingRule) {\n throw new InvalidRequestError(\n 'No active rule found for this URL/domain',\n 'RuleNotFound',\n )\n }\n\n return await this.db.transaction(async (txn) => {\n const event = await txn.db\n .insertInto('safelink_event')\n .values({\n eventType: 'removeRule',\n url,\n pattern,\n action: existingRule.action,\n reason: existingRule.reason,\n createdBy,\n comment: comment || null,\n createdAt: new Date().toISOString(),\n })\n .returningAll()\n .executeTakeFirstOrThrow()\n\n await txn.db\n .deleteFrom('safelink_rule')\n .where('url', '=', url)\n .where('pattern', '=', pattern)\n .execute()\n\n return event\n })\n }\n\n async getActiveRule(url: string, pattern: SafelinkPatternType) {\n const rule = await this.db.db\n .selectFrom('safelink_rule')\n .selectAll()\n .where('url', '=', url)\n .where('pattern', '=', pattern)\n .executeTakeFirst()\n\n if (!rule) {\n return null\n }\n\n return rule\n }\n\n async getActiveRules({\n cursor,\n limit = 50,\n urls,\n patternType,\n actions,\n reason,\n createdBy,\n direction = 'desc',\n }: {\n cursor?: string\n limit?: number\n urls?: string[]\n patternType?: SafelinkPatternType\n actions?: SafelinkActionType[]\n reason?: SafelinkReasonType\n createdBy?: string\n direction?: 'asc' | 'desc'\n } = {}): Promise<{\n rules: Selectable<SafelinkRule>[]\n cursor?: string\n }> {\n let query = this.db.db.selectFrom('safelink_rule').selectAll()\n\n if (urls && urls.length > 0) {\n query = query.where('url', 'in', urls)\n }\n\n if (patternType) {\n query = query.where('pattern', '=', patternType)\n }\n\n if (actions && actions.length > 0) {\n query = query.where('action', 'in', actions)\n }\n\n if (reason) {\n query = query.where('reason', '=', reason)\n }\n\n if (createdBy) {\n query = query.where('createdBy', '=', createdBy)\n }\n\n if (cursor) {\n query = query.where(\n 'id',\n direction === 'asc' ? '>' : '<',\n parseInt(cursor, 10),\n )\n }\n\n const rules = await query.orderBy('id', direction).limit(limit).execute()\n\n return {\n rules,\n cursor: rules.at(-1)?.id?.toString(),\n }\n }\n\n async queryEvents({\n cursor,\n limit = 50,\n urls,\n patternType,\n direction = 'desc',\n }: {\n cursor?: string\n limit?: number\n urls?: string[]\n patternType?: SafelinkPatternType\n direction?: 'asc' | 'desc'\n } = {}): Promise<{\n events: Selectable<SafelinkEvent>[]\n cursor?: string\n }> {\n let query = this.db.db.selectFrom('safelink_event').selectAll()\n\n if (urls && urls.length > 0) {\n query = query.where('url', 'in', urls)\n }\n\n if (patternType) {\n query = query.where('pattern', '=', patternType)\n }\n\n if (cursor) {\n query = query.where(\n 'id',\n direction === 'asc' ? '>' : '<',\n parseInt(cursor, 10),\n )\n }\n\n const events = await query.orderBy('id', direction).limit(limit).execute()\n\n return {\n events,\n cursor: events.at(-1)?.id?.toString(),\n }\n }\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;gBAAZ,EAAE,EAAE,QAAQ;IAE/B,MAAM,CAAC,OAAO,KACJ,IAAI,QAAQ;IAGtB,qBAAqB,CACnB,MAAM,EAAE,UAAU,CAAC,eAAe,CAAC,GAClC,mBAAmB;IA4BhB,cAAc,CAClB,gBAAgB,EAAE,gBAAgB,GACjC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;IAwDjC,0BAA0B,CAC9B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC;IAYxC,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;IA+CI,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;IAsCI,0BAA0B,CAC9B,GAAG,EAAE,IAAI,GACR,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;IAanC,oBAAoB,CACxB,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC;IAcV,kBAAkB,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC;CAajB"}
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 +1 @@
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((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((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 +1 @@
1
- {"version":3,"file":"outbox.d.ts","sourceRoot":"","sources":["../../src/sequencer/outbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAwB,MAAM,iBAAiB,CAAA;AAEnE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAErD,MAAM,MAAM,UAAU,GAAG;IACvB,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,qBAAa,MAAM;IAQR,SAAS,EAAE,SAAS;IAP7B,OAAO,CAAC,QAAQ,CAAQ;IACxB,QAAQ,SAAK;IAEb,aAAa,EAAE,SAAS,EAAE,CAAA;IAC1B,SAAS,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;gBAGxB,SAAS,EAAE,SAAS,EAC3B,IAAI,GAAE,OAAO,CAAC,UAAU,CAAM;IAgBzB,MAAM,CACX,cAAc,CAAC,EAAE,MAAM,EACvB,MAAM,CAAC,EAAE,WAAW,GACnB,cAAc,CAAC,SAAS,CAAC;IAsErB,WAAW,CAAC,cAAc,EAAE,MAAM;CAgB1C"}
1
+ {"version":3,"file":"outbox.d.ts","sourceRoot":"","sources":["../../src/sequencer/outbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAwB,MAAM,iBAAiB,CAAA;AAEnE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAErD,MAAM,MAAM,UAAU,GAAG;IACvB,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,qBAAa,MAAM;IAQR,SAAS,EAAE,SAAS;IAP7B,OAAO,CAAC,QAAQ,CAAQ;IACxB,QAAQ,SAAK;IAEb,aAAa,EAAE,SAAS,EAAE,CAAA;IAC1B,SAAS,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;IAEjC,YACS,SAAS,EAAE,SAAS,EAC3B,IAAI,GAAE,OAAO,CAAC,UAAU,CAAM,EAK/B;IAWM,MAAM,CACX,cAAc,CAAC,EAAE,MAAM,EACvB,MAAM,CAAC,EAAE,WAAW,GACnB,cAAc,CAAC,SAAS,CAAC,CAmE3B;IAGM,WAAW,CAAC,cAAc,EAAE,MAAM,4CAexC;CACF"}