@atproto/ozone 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/api/index.d.ts.map +1 -1
  3. package/dist/api/index.js +2 -0
  4. package/dist/api/index.js.map +1 -1
  5. package/dist/api/label/queryLabels.d.ts.map +1 -1
  6. package/dist/api/label/queryLabels.js +13 -21
  7. package/dist/api/label/queryLabels.js.map +1 -1
  8. package/dist/api/report/queryActivities.d.ts +4 -0
  9. package/dist/api/report/queryActivities.d.ts.map +1 -0
  10. package/dist/api/report/queryActivities.js +36 -0
  11. package/dist/api/report/queryActivities.js.map +1 -0
  12. package/dist/assignment/index.d.ts.map +1 -1
  13. package/dist/assignment/index.js +9 -12
  14. package/dist/assignment/index.js.map +1 -1
  15. package/dist/background.d.ts +5 -3
  16. package/dist/background.d.ts.map +1 -1
  17. package/dist/background.js +13 -4
  18. package/dist/background.js.map +1 -1
  19. package/dist/context.js +1 -1
  20. package/dist/context.js.map +1 -1
  21. package/dist/daemon/context.js +1 -1
  22. package/dist/daemon/context.js.map +1 -1
  23. package/dist/daemon/event-pusher.d.ts +7 -1
  24. package/dist/daemon/event-pusher.d.ts.map +1 -1
  25. package/dist/daemon/verification-listener.d.ts +1 -1
  26. package/dist/daemon/verification-listener.d.ts.map +1 -1
  27. package/dist/daemon/verification-listener.js +10 -4
  28. package/dist/daemon/verification-listener.js.map +1 -1
  29. package/dist/db/index.d.ts +4 -5
  30. package/dist/db/index.d.ts.map +1 -1
  31. package/dist/db/index.js +2 -1
  32. package/dist/db/index.js.map +1 -1
  33. package/dist/db/migrations/20241220T144630860Z-stats-materialized-views.d.ts +1 -2
  34. package/dist/db/migrations/20241220T144630860Z-stats-materialized-views.d.ts.map +1 -1
  35. package/dist/db/migrations/20241220T144630860Z-stats-materialized-views.js.map +1 -1
  36. package/dist/db/migrations/20250718T150931000Z-update-appeal-reason-stats.d.ts +1 -2
  37. package/dist/db/migrations/20250718T150931000Z-update-appeal-reason-stats.d.ts.map +1 -1
  38. package/dist/db/migrations/20250718T150931000Z-update-appeal-reason-stats.js.map +1 -1
  39. package/dist/db/migrations/20260602T120000000Z-add-report-activity-created-index.d.ts +4 -0
  40. package/dist/db/migrations/20260602T120000000Z-add-report-activity-created-index.d.ts.map +1 -0
  41. package/dist/db/migrations/20260602T120000000Z-add-report-activity-created-index.js +15 -0
  42. package/dist/db/migrations/20260602T120000000Z-add-report-activity-created-index.js.map +1 -0
  43. package/dist/db/migrations/index.d.ts +1 -0
  44. package/dist/db/migrations/index.d.ts.map +1 -1
  45. package/dist/db/migrations/index.js +1 -0
  46. package/dist/db/migrations/index.js.map +1 -1
  47. package/dist/db/migrations/provider.d.ts +2 -1
  48. package/dist/db/migrations/provider.d.ts.map +1 -1
  49. package/dist/db/migrations/provider.js.map +1 -1
  50. package/dist/db/pagination.d.ts +4 -3
  51. package/dist/db/pagination.d.ts.map +1 -1
  52. package/dist/db/pagination.js +4 -4
  53. package/dist/db/pagination.js.map +1 -1
  54. package/dist/db/types.d.ts +1 -1
  55. package/dist/db/types.d.ts.map +1 -1
  56. package/dist/db/types.js.map +1 -1
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +23 -13
  59. package/dist/index.js.map +1 -1
  60. package/dist/jetstream/service.d.ts +1 -1
  61. package/dist/jetstream/service.d.ts.map +1 -1
  62. package/dist/jetstream/service.js +3 -1
  63. package/dist/jetstream/service.js.map +1 -1
  64. package/dist/lexicon/index.d.ts +11 -0
  65. package/dist/lexicon/index.d.ts.map +1 -1
  66. package/dist/lexicon/index.js +18 -0
  67. package/dist/lexicon/index.js.map +1 -1
  68. package/dist/lexicon/lexicons.d.ts +338 -0
  69. package/dist/lexicon/lexicons.d.ts.map +1 -1
  70. package/dist/lexicon/lexicons.js +173 -0
  71. package/dist/lexicon/lexicons.js.map +1 -1
  72. package/dist/lexicon/types/app/bsky/notification/defs.d.ts +1 -0
  73. package/dist/lexicon/types/app/bsky/notification/defs.d.ts.map +1 -1
  74. package/dist/lexicon/types/app/bsky/notification/defs.js.map +1 -1
  75. package/dist/lexicon/types/chat/bsky/notification/defs.d.ts +19 -0
  76. package/dist/lexicon/types/chat/bsky/notification/defs.d.ts.map +1 -0
  77. package/dist/lexicon/types/chat/bsky/notification/defs.js +19 -0
  78. package/dist/lexicon/types/chat/bsky/notification/defs.js.map +1 -0
  79. package/dist/lexicon/types/chat/bsky/notification/getPreferences.d.ts +20 -0
  80. package/dist/lexicon/types/chat/bsky/notification/getPreferences.d.ts.map +1 -0
  81. package/dist/lexicon/types/chat/bsky/notification/getPreferences.js +5 -0
  82. package/dist/lexicon/types/chat/bsky/notification/getPreferences.js.map +1 -0
  83. package/dist/lexicon/types/chat/bsky/notification/putPreferences.d.ts +26 -0
  84. package/dist/lexicon/types/chat/bsky/notification/putPreferences.d.ts.map +1 -0
  85. package/dist/lexicon/types/chat/bsky/notification/putPreferences.js +5 -0
  86. package/dist/lexicon/types/chat/bsky/notification/putPreferences.js.map +1 -0
  87. package/dist/lexicon/types/tools/ozone/report/defs.d.ts +1 -0
  88. package/dist/lexicon/types/tools/ozone/report/defs.d.ts.map +1 -1
  89. package/dist/lexicon/types/tools/ozone/report/defs.js.map +1 -1
  90. package/dist/lexicon/types/tools/ozone/report/queryActivities.d.ts +32 -0
  91. package/dist/lexicon/types/tools/ozone/report/queryActivities.d.ts.map +1 -0
  92. package/dist/lexicon/types/tools/ozone/report/queryActivities.js +5 -0
  93. package/dist/lexicon/types/tools/ozone/report/queryActivities.js.map +1 -0
  94. package/dist/mod-service/index.d.ts.map +1 -1
  95. package/dist/mod-service/index.js +28 -52
  96. package/dist/mod-service/index.js.map +1 -1
  97. package/dist/mod-service/report.d.ts +1 -0
  98. package/dist/mod-service/report.d.ts.map +1 -1
  99. package/dist/mod-service/report.js +16 -0
  100. package/dist/mod-service/report.js.map +1 -1
  101. package/dist/mod-service/status.d.ts +23 -128
  102. package/dist/mod-service/status.d.ts.map +1 -1
  103. package/dist/mod-service/views.js +7 -11
  104. package/dist/mod-service/views.js.map +1 -1
  105. package/dist/queue/service.js +1 -3
  106. package/dist/queue/service.js.map +1 -1
  107. package/dist/report/activity.d.ts +31 -2
  108. package/dist/report/activity.d.ts.map +1 -1
  109. package/dist/report/activity.js +27 -1
  110. package/dist/report/activity.js.map +1 -1
  111. package/dist/report/stats.d.ts.map +1 -1
  112. package/dist/report/stats.js.map +1 -1
  113. package/dist/scheduled-action/service.d.ts.map +1 -1
  114. package/dist/scheduled-action/service.js +16 -20
  115. package/dist/scheduled-action/service.js.map +1 -1
  116. package/dist/set/service.d.ts +10 -1
  117. package/dist/set/service.d.ts.map +1 -1
  118. package/dist/set/service.js +5 -2
  119. package/dist/set/service.js.map +1 -1
  120. package/dist/team/index.d.ts.map +1 -1
  121. package/dist/team/index.js +5 -4
  122. package/dist/team/index.js.map +1 -1
  123. package/dist/verification/issuer.d.ts +13 -3
  124. package/dist/verification/issuer.d.ts.map +1 -1
  125. package/dist/verification/service.d.ts +13 -1
  126. package/dist/verification/service.d.ts.map +1 -1
  127. package/dist/verification/service.js +1 -1
  128. package/dist/verification/service.js.map +1 -1
  129. package/package.json +12 -11
  130. package/src/api/index.ts +2 -0
  131. package/src/api/label/queryLabels.ts +11 -14
  132. package/src/api/report/queryActivities.ts +64 -0
  133. package/src/assignment/index.ts +15 -18
  134. package/src/background.ts +19 -4
  135. package/src/context.ts +1 -1
  136. package/src/daemon/context.ts +1 -1
  137. package/src/daemon/verification-listener.ts +9 -4
  138. package/src/db/index.ts +1 -1
  139. package/src/db/migrations/20241220T144630860Z-stats-materialized-views.ts +1 -2
  140. package/src/db/migrations/20250718T150931000Z-update-appeal-reason-stats.ts +1 -2
  141. package/src/db/migrations/20260602T120000000Z-add-report-activity-created-index.ts +17 -0
  142. package/src/db/migrations/index.ts +1 -0
  143. package/src/db/migrations/provider.ts +2 -1
  144. package/src/db/pagination.ts +18 -18
  145. package/src/db/types.ts +3 -1
  146. package/src/index.ts +25 -15
  147. package/src/jetstream/service.ts +3 -1
  148. package/src/mod-service/index.ts +78 -71
  149. package/src/mod-service/report.ts +24 -3
  150. package/src/mod-service/views.ts +16 -16
  151. package/src/queue/service.ts +5 -5
  152. package/src/report/activity.ts +47 -0
  153. package/src/report/stats.ts +5 -3
  154. package/src/scheduled-action/service.ts +22 -20
  155. package/src/set/service.ts +17 -14
  156. package/src/team/index.ts +6 -5
  157. package/src/verification/service.ts +2 -2
  158. package/tests/3p-labeler.test.ts +2 -2
  159. package/tests/_util.ts +8 -25
  160. package/tests/account-strikes.test.ts +1 -1
  161. package/tests/ack-all-subjects-of-account.test.ts +1 -1
  162. package/tests/age-assurance.test.ts +1 -1
  163. package/tests/blob-divert.test.ts +1 -1
  164. package/tests/communication-templates.test.ts +1 -1
  165. package/tests/content-tagger.test.ts +1 -1
  166. package/tests/db.test.ts +1 -1
  167. package/tests/expiring-label.test.ts +1 -1
  168. package/tests/expiring-tags.test.ts +1 -1
  169. package/tests/get-account-timeline.test.ts +1 -1
  170. package/tests/get-config.test.ts +1 -1
  171. package/tests/get-lists.test.ts +2 -1
  172. package/tests/get-profiles.test.ts +1 -1
  173. package/tests/get-record.test.ts +1 -1
  174. package/tests/get-records.test.ts +1 -1
  175. package/tests/get-repo.test.ts +1 -1
  176. package/tests/get-report.test.ts +1 -1
  177. package/tests/get-reporter-stats.test.ts +1 -1
  178. package/tests/get-repos.test.ts +1 -1
  179. package/tests/get-starter-pack.test.ts +1 -1
  180. package/tests/get-subjects.test.ts +1 -1
  181. package/tests/mod-tool.test.ts +1 -1
  182. package/tests/moderation-appeals.test.ts +1 -1
  183. package/tests/moderation-events.test.ts +1 -1
  184. package/tests/moderation-status-tags.test.ts +1 -1
  185. package/tests/moderation-statuses.test.ts +1 -1
  186. package/tests/moderation.test.ts +1 -1
  187. package/tests/protected-tags.test.ts +1 -1
  188. package/tests/query-labels.test.ts +1 -1
  189. package/tests/query-reports.test.ts +1 -1
  190. package/tests/queue-assignment.test.ts +1 -1
  191. package/tests/queue-router.test.ts +1 -1
  192. package/tests/queues.test.ts +1 -1
  193. package/tests/record-and-account-events.test.ts +1 -1
  194. package/tests/repo-search.test.ts +2 -2
  195. package/tests/report-action.test.ts +1 -1
  196. package/tests/report-activity.test.ts +145 -1
  197. package/tests/report-assignment.test.ts +1 -1
  198. package/tests/report-muting.test.ts +1 -1
  199. package/tests/report-reason.test.ts +1 -1
  200. package/tests/report-reassign-queue.test.ts +1 -1
  201. package/tests/report-routing.test.ts +1 -1
  202. package/tests/report-stats.test.ts +1 -1
  203. package/tests/revoke-account-credentials.test.ts +1 -1
  204. package/tests/safelink.test.ts +1 -1
  205. package/tests/scheduled-action-processor.test.ts +1 -1
  206. package/tests/scheduled-action.test.ts +1 -1
  207. package/tests/sequencer.test.ts +1 -1
  208. package/tests/server.test.ts +9 -12
  209. package/tests/sets.test.ts +1 -1
  210. package/tests/settings.test.ts +1 -1
  211. package/tests/strike-expiry-processor.test.ts +1 -1
  212. package/tests/subject-priority-score.test.ts +1 -1
  213. package/tests/takedown.test.ts +1 -1
  214. package/tests/team.test.ts +1 -1
  215. package/tests/verification-listener.test.ts +40 -13
  216. package/tests/verification.test.ts +1 -1
  217. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/team/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { Selectable } from 'kysely'\nimport AtpAgent from '@atproto/api'\nimport { chunkArray } from '@atproto/common'\nimport { InvalidRequestError } from '@atproto/xrpc-server'\nimport { Database } from '../db/index.js'\nimport { Member } from '../db/schema/member.js'\nimport { ids } from '../lexicon/lexicons.js'\nimport { ProfileViewDetailed } from '../lexicon/types/app/bsky/actor/defs.js'\nimport { Member as TeamMember } from '../lexicon/types/tools/ozone/team/defs.js'\nimport { httpLogger } from '../logger.js'\nimport { AuthHeaders } from '../mod-service/views.js'\n\nexport type TeamServiceCreator = (db: Database) => TeamService\n\nexport class TeamService {\n constructor(\n public db: Database,\n private appviewAgent: AtpAgent,\n private appviewDid: string,\n private createAuthHeaders: (\n aud: string,\n method: string,\n ) => Promise<AuthHeaders>,\n ) {}\n\n static creator(\n appviewAgent: AtpAgent,\n appviewDid: string,\n createAuthHeaders: (aud: string, method: string) => Promise<AuthHeaders>,\n ) {\n return (db: Database) =>\n new TeamService(db, appviewAgent, appviewDid, createAuthHeaders)\n }\n\n async list({\n cursor,\n limit = 25,\n roles,\n disabled,\n q,\n }: {\n q?: string\n cursor?: string\n limit?: number\n disabled?: boolean\n roles?: string[]\n }): Promise<{ members: Selectable<Member>[]; cursor?: string }> {\n let builder = this.db.db.selectFrom('member').selectAll()\n if (cursor) {\n builder = builder.where('createdAt', '>', new Date(cursor))\n }\n if (roles !== undefined) {\n const knownRoles = roles.filter(\n (r) =>\n r === 'tools.ozone.team.defs#roleAdmin' ||\n r === 'tools.ozone.team.defs#roleModerator' ||\n r === 'tools.ozone.team.defs#roleVerifier' ||\n r === 'tools.ozone.team.defs#roleTriage',\n )\n\n // Optimization: no need to query to know that no values will be returned\n if (!knownRoles.length) return { members: [] }\n\n builder = builder.where('role', 'in', knownRoles)\n }\n if (disabled !== undefined) {\n builder = builder.where('disabled', disabled ? 'is' : 'is not', true)\n }\n if (q) {\n builder = builder.where((qb) =>\n qb\n .orWhere('handle', 'ilike', `%${q}%`)\n .orWhere('displayName', 'ilike', `%${q}%`),\n )\n }\n\n const members = await builder\n .limit(limit)\n .orderBy('createdAt', 'asc')\n .orderBy('handle', 'asc')\n .execute()\n\n return { members, cursor: members.at(-1)?.createdAt.toISOString() }\n }\n\n async create({\n role,\n did,\n disabled,\n updatedAt,\n createdAt,\n lastUpdatedBy,\n }: Omit<Selectable<Member>, 'createdAt' | 'updatedAt'> & {\n createdAt?: Date\n updatedAt?: Date\n }): Promise<Selectable<Member>> {\n const now = new Date()\n const newMember = await this.db.db\n .insertInto('member')\n .values({\n role,\n did,\n disabled,\n lastUpdatedBy,\n updatedAt: updatedAt || now,\n createdAt: createdAt || now,\n })\n .returningAll()\n .executeTakeFirstOrThrow()\n\n return newMember\n }\n\n async upsert({\n role,\n did,\n lastUpdatedBy,\n }: Pick<\n Selectable<Member>,\n 'role' | 'did' | 'lastUpdatedBy'\n >): Promise<void> {\n const now = new Date()\n await this.db.db\n .insertInto('member')\n .values({\n role,\n did,\n lastUpdatedBy,\n disabled: false,\n updatedAt: now,\n createdAt: now,\n })\n .onConflict((oc) =>\n oc.column('did').doUpdateSet({ role, updatedAt: now, lastUpdatedBy }),\n )\n .execute()\n }\n\n async update(\n did: string,\n updates: Partial<\n Pick<\n Selectable<Member>,\n 'role' | 'disabled' | 'lastUpdatedBy' | 'updatedAt'\n >\n >,\n ): Promise<Selectable<Member>> {\n const { role, disabled, lastUpdatedBy, updatedAt = new Date() } = updates\n const updatedMember = await this.db.db\n .updateTable('member')\n .where('did', '=', did)\n .set({\n role,\n disabled,\n lastUpdatedBy,\n updatedAt,\n })\n .returningAll()\n .executeTakeFirstOrThrow()\n\n return updatedMember\n }\n\n async delete(did: string): Promise<void> {\n await this.db.db.deleteFrom('member').where('did', '=', did).execute()\n }\n\n async assertCanDelete(did: string): Promise<void> {\n const memberExists = await this.doesMemberExist(did)\n\n if (!memberExists) {\n throw new InvalidRequestError('member not found', 'MemberNotFound')\n }\n }\n\n async doesMemberExist(did: string): Promise<boolean> {\n const member = await this.db.db\n .selectFrom('member')\n .select('did')\n .where('did', '=', did)\n .executeTakeFirst()\n\n return !!member\n }\n\n async getMember(did: string): Promise<Selectable<Member> | undefined> {\n const member = await this.db.db\n .selectFrom('member')\n .selectAll()\n .where('did', '=', did)\n .executeTakeFirst()\n\n return member\n }\n\n getMemberRole(member?: Selectable<Member>) {\n const isAdmin = member?.role === 'tools.ozone.team.defs#roleAdmin'\n const isModerator =\n isAdmin || member?.role === 'tools.ozone.team.defs#roleModerator'\n const isTriage =\n isModerator || member?.role === 'tools.ozone.team.defs#roleTriage'\n const isVerifier =\n isAdmin || member?.role === 'tools.ozone.team.defs#roleVerifier'\n\n return {\n isModerator,\n isAdmin,\n isTriage,\n isVerifier,\n }\n }\n\n // getProfiles() only allows 25 DIDs at a time so we need to query in chunks\n async getProfiles(dids: string[]): Promise<Map<string, ProfileViewDetailed>> {\n const profiles = new Map<string, ProfileViewDetailed>()\n\n try {\n const headers = await this.createAuthHeaders(\n this.appviewDid,\n ids.AppBskyActorGetProfiles,\n )\n\n for (const actors of chunkArray(dids, 25)) {\n const { data } = await this.appviewAgent.getProfiles(\n { actors },\n headers,\n )\n\n data.profiles.forEach((profile) => {\n profiles.set(profile.did, profile)\n })\n }\n } catch (err) {\n httpLogger.error({ err, dids }, 'Failed to get profiles for team members')\n }\n\n return profiles\n }\n\n async syncMemberProfiles(): Promise<void> {\n let lastDid = ''\n // Max 25 profiles can be fetched at a time so let's pull 25 members at a time from the db and update their profile details\n do {\n const members = await this.db.db\n .selectFrom('member')\n .select(['did'])\n .limit(25)\n .if(!!lastDid, (q) => q.where('did', '>', lastDid))\n .orderBy('did', 'asc')\n .execute()\n\n const dids = members.map((member) => member.did)\n const profiles = await this.getProfiles(dids)\n\n for (const profile of profiles.values()) {\n await this.db.db\n .updateTable('member')\n .where('did', '=', profile.did)\n .set({\n handle: profile.handle,\n displayName: profile.displayName || null,\n })\n .execute()\n }\n\n lastDid = dids.at(-1) || ''\n } while (lastDid)\n }\n\n async viewByDids(dids: string[]): Promise<Map<string, TeamMember>> {\n if (!dids.length) return new Map()\n const members = await this.db.db\n .selectFrom('member')\n .selectAll()\n .where('did', 'in', dids)\n .execute()\n const memberViews = await this.view(members)\n return new Map(memberViews.map((m) => [m.did, m]))\n }\n\n async view(members: Selectable<Member>[]): Promise<TeamMember[]> {\n const profiles = await this.getProfiles(members.map(({ did }) => did))\n return members.map((member) => {\n return {\n did: member.did,\n role: member.role,\n disabled: member.disabled,\n profile: profiles.get(member.did),\n createdAt: member.createdAt.toISOString(),\n updatedAt: member.updatedAt.toISOString(),\n lastUpdatedBy: member.lastUpdatedBy,\n }\n })\n }\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/team/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { Selectable } from 'kysely'\nimport AtpAgent from '@atproto/api'\nimport { chunkArray } from '@atproto/common'\nimport { InvalidRequestError } from '@atproto/xrpc-server'\nimport { Database } from '../db/index.js'\nimport { Member } from '../db/schema/member.js'\nimport { ids } from '../lexicon/lexicons.js'\nimport { ProfileViewDetailed } from '../lexicon/types/app/bsky/actor/defs.js'\nimport { Member as TeamMember } from '../lexicon/types/tools/ozone/team/defs.js'\nimport { httpLogger } from '../logger.js'\nimport { AuthHeaders } from '../mod-service/views.js'\n\nexport type TeamServiceCreator = (db: Database) => TeamService\n\nexport class TeamService {\n constructor(\n public db: Database,\n private appviewAgent: AtpAgent,\n private appviewDid: string,\n private createAuthHeaders: (\n aud: string,\n method: string,\n ) => Promise<AuthHeaders>,\n ) {}\n\n static creator(\n appviewAgent: AtpAgent,\n appviewDid: string,\n createAuthHeaders: (aud: string, method: string) => Promise<AuthHeaders>,\n ) {\n return (db: Database) =>\n new TeamService(db, appviewAgent, appviewDid, createAuthHeaders)\n }\n\n async list({\n cursor,\n limit = 25,\n roles,\n disabled,\n q,\n }: {\n q?: string\n cursor?: string\n limit?: number\n disabled?: boolean\n roles?: string[]\n }): Promise<{ members: Selectable<Member>[]; cursor?: string }> {\n let builder = this.db.db.selectFrom('member').selectAll()\n if (cursor) {\n builder = builder.where('createdAt', '>', new Date(cursor))\n }\n if (roles !== undefined) {\n const knownRoles = roles.filter(\n (r) =>\n r === 'tools.ozone.team.defs#roleAdmin' ||\n r === 'tools.ozone.team.defs#roleModerator' ||\n r === 'tools.ozone.team.defs#roleVerifier' ||\n r === 'tools.ozone.team.defs#roleTriage',\n )\n\n // Optimization: no need to query to know that no values will be returned\n if (!knownRoles.length) return { members: [] }\n\n builder = builder.where('role', 'in', knownRoles)\n }\n if (disabled !== undefined) {\n builder = builder.where('disabled', disabled ? 'is' : 'is not', true)\n }\n if (q) {\n builder = builder.where((eb) =>\n eb.or([\n eb('handle', 'ilike', `%${q}%`),\n eb('displayName', 'ilike', `%${q}%`),\n ]),\n )\n }\n\n const members = await builder\n .limit(limit)\n .orderBy('createdAt', 'asc')\n .orderBy('handle', 'asc')\n .execute()\n\n return { members, cursor: members.at(-1)?.createdAt.toISOString() }\n }\n\n async create({\n role,\n did,\n disabled,\n updatedAt,\n createdAt,\n lastUpdatedBy,\n }: Omit<Selectable<Member>, 'createdAt' | 'updatedAt'> & {\n createdAt?: Date\n updatedAt?: Date\n }): Promise<Selectable<Member>> {\n const now = new Date()\n const newMember = await this.db.db\n .insertInto('member')\n .values({\n role,\n did,\n disabled,\n lastUpdatedBy,\n updatedAt: updatedAt || now,\n createdAt: createdAt || now,\n })\n .returningAll()\n .executeTakeFirstOrThrow()\n\n return newMember\n }\n\n async upsert({\n role,\n did,\n lastUpdatedBy,\n }: Pick<\n Selectable<Member>,\n 'role' | 'did' | 'lastUpdatedBy'\n >): Promise<void> {\n const now = new Date()\n await this.db.db\n .insertInto('member')\n .values({\n role,\n did,\n lastUpdatedBy,\n disabled: false,\n updatedAt: now,\n createdAt: now,\n })\n .onConflict((oc) =>\n oc.column('did').doUpdateSet({ role, updatedAt: now, lastUpdatedBy }),\n )\n .execute()\n }\n\n async update(\n did: string,\n updates: Partial<\n Pick<\n Selectable<Member>,\n 'role' | 'disabled' | 'lastUpdatedBy' | 'updatedAt'\n >\n >,\n ): Promise<Selectable<Member>> {\n const { role, disabled, lastUpdatedBy, updatedAt = new Date() } = updates\n const updatedMember = await this.db.db\n .updateTable('member')\n .where('did', '=', did)\n .set({\n role,\n disabled,\n lastUpdatedBy,\n updatedAt,\n })\n .returningAll()\n .executeTakeFirstOrThrow()\n\n return updatedMember\n }\n\n async delete(did: string): Promise<void> {\n await this.db.db.deleteFrom('member').where('did', '=', did).execute()\n }\n\n async assertCanDelete(did: string): Promise<void> {\n const memberExists = await this.doesMemberExist(did)\n\n if (!memberExists) {\n throw new InvalidRequestError('member not found', 'MemberNotFound')\n }\n }\n\n async doesMemberExist(did: string): Promise<boolean> {\n const member = await this.db.db\n .selectFrom('member')\n .select('did')\n .where('did', '=', did)\n .executeTakeFirst()\n\n return !!member\n }\n\n async getMember(did: string): Promise<Selectable<Member> | undefined> {\n const member = await this.db.db\n .selectFrom('member')\n .selectAll()\n .where('did', '=', did)\n .executeTakeFirst()\n\n return member\n }\n\n getMemberRole(member?: Selectable<Member>) {\n const isAdmin = member?.role === 'tools.ozone.team.defs#roleAdmin'\n const isModerator =\n isAdmin || member?.role === 'tools.ozone.team.defs#roleModerator'\n const isTriage =\n isModerator || member?.role === 'tools.ozone.team.defs#roleTriage'\n const isVerifier =\n isAdmin || member?.role === 'tools.ozone.team.defs#roleVerifier'\n\n return {\n isModerator,\n isAdmin,\n isTriage,\n isVerifier,\n }\n }\n\n // getProfiles() only allows 25 DIDs at a time so we need to query in chunks\n async getProfiles(dids: string[]): Promise<Map<string, ProfileViewDetailed>> {\n const profiles = new Map<string, ProfileViewDetailed>()\n\n try {\n const headers = await this.createAuthHeaders(\n this.appviewDid,\n ids.AppBskyActorGetProfiles,\n )\n\n for (const actors of chunkArray(dids, 25)) {\n const { data } = await this.appviewAgent.getProfiles(\n { actors },\n headers,\n )\n\n data.profiles.forEach((profile) => {\n profiles.set(profile.did, profile)\n })\n }\n } catch (err) {\n httpLogger.error({ err, dids }, 'Failed to get profiles for team members')\n }\n\n return profiles\n }\n\n async syncMemberProfiles(): Promise<void> {\n let lastDid = ''\n // Max 25 profiles can be fetched at a time so let's pull 25 members at a time from the db and update their profile details\n do {\n const members = await this.db.db\n .selectFrom('member')\n .select(['did'])\n .limit(25)\n .$if(!!lastDid, (q) => q.where('did', '>', lastDid))\n .orderBy('did', 'asc')\n .execute()\n\n const dids = members.map((member) => member.did)\n const profiles = await this.getProfiles(dids)\n\n for (const profile of profiles.values()) {\n await this.db.db\n .updateTable('member')\n .where('did', '=', profile.did)\n .set({\n handle: profile.handle,\n displayName: profile.displayName || null,\n })\n .execute()\n }\n\n lastDid = dids.at(-1) || ''\n } while (lastDid)\n }\n\n async viewByDids(dids: string[]): Promise<Map<string, TeamMember>> {\n if (!dids.length) return new Map()\n const members = await this.db.db\n .selectFrom('member')\n .selectAll()\n .where('did', 'in', dids)\n .execute()\n const memberViews = await this.view(members)\n return new Map(memberViews.map((m) => [m.did, m]))\n }\n\n async view(members: Selectable<Member>[]): Promise<TeamMember[]> {\n const profiles = await this.getProfiles(members.map(({ did }) => did))\n return members.map((member) => {\n return {\n did: member.did,\n role: member.role,\n disabled: member.disabled,\n profile: profiles.get(member.did),\n createdAt: member.createdAt.toISOString(),\n updatedAt: member.updatedAt.toISOString(),\n lastUpdatedBy: member.lastUpdatedBy,\n }\n })\n }\n}\n"]}
@@ -1,7 +1,5 @@
1
- import { Selectable } from 'kysely';
2
1
  import { Agent } from '@atproto/api';
3
2
  import { VerifierConfig } from '../config/index.js';
4
- import { Verification } from '../db/schema/verification.js';
5
3
  export type VerificationInput = {
6
4
  displayName: string;
7
5
  handle: string;
@@ -17,7 +15,19 @@ export declare class VerificationIssuer {
17
15
  static creator(): (verifierConfig: VerifierConfig) => VerificationIssuer;
18
16
  getAgent(): Promise<Agent>;
19
17
  verify(verifications: VerificationInput[]): Promise<{
20
- grantedVerifications: Selectable<Verification>[];
18
+ grantedVerifications: {
19
+ cid: string;
20
+ createdAt: string;
21
+ displayName: string;
22
+ handle: string;
23
+ issuer: string;
24
+ revokeReason: string | null;
25
+ revokedAt: string | null;
26
+ revokedBy: string | null;
27
+ subject: string;
28
+ updatedAt: string;
29
+ uri: string;
30
+ }[];
21
31
  failedVerifications: {
22
32
  $type: 'tools.ozone.verification.grantVerifications#grantError';
23
33
  subject: string;
@@ -1 +1 @@
1
- {"version":3,"file":"issuer.d.ts","sourceRoot":"","sources":["../../src/verification/issuer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EAAE,KAAK,EAA4B,MAAM,cAAc,CAAA;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAE3D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG,CACtC,cAAc,EAAE,cAAc,KAC3B,kBAAkB,CAAA;AAIvB,qBAAa,kBAAkB;IAGjB,OAAO,CAAC,cAAc;IAFlC,OAAO,CAAC,OAAO,CAA0D;IACzE,OAAO,CAAC,KAAK,CAA0B;IACvC,YAAoB,cAAc,EAAE,cAAc,EAAI;IAEtD,MAAM,CAAC,OAAO,qBACY,cAAc,wBAEvC;IAEK,QAAQ,mBAqBb;IAEK,MAAM,CAAC,aAAa,EAAE,iBAAiB,EAAE;;;mBAGpC,wDAAwD;qBACtD,MAAM;mBACR,MAAM;;OAmDhB;IAEK,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE;;;iBAED,MAAM;mBAAS,MAAM;;OAiC5D;CACF"}
1
+ {"version":3,"file":"issuer.d.ts","sourceRoot":"","sources":["../../src/verification/issuer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAA4B,MAAM,cAAc,CAAA;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAGnD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG,CACtC,cAAc,EAAE,cAAc,KAC3B,kBAAkB,CAAA;AAIvB,qBAAa,kBAAkB;IAGjB,OAAO,CAAC,cAAc;IAFlC,OAAO,CAAC,OAAO,CAA0D;IACzE,OAAO,CAAC,KAAK,CAA0B;IACvC,YAAoB,cAAc,EAAE,cAAc,EAAI;IAEtD,MAAM,CAAC,OAAO,qBACY,cAAc,wBAEvC;IAEK,QAAQ,mBAqBb;IAEK,MAAM,CAAC,aAAa,EAAE,iBAAiB,EAAE;;;;;;;;;;;;;;;mBAGpC,wDAAwD;qBACtD,MAAM;mBACR,MAAM;;OAmDhB;IAEK,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE;;;iBAED,MAAM;mBAAS,MAAM;;OAiC5D;CACF"}
@@ -7,7 +7,19 @@ export declare class VerificationService {
7
7
  db: Database;
8
8
  constructor(db: Database);
9
9
  static creator(): (db: Database) => VerificationService;
10
- create(verifications: Pick<Verification, 'uri' | 'issuer' | 'subject' | 'handle' | 'displayName' | 'createdAt' | 'cid'>[]): Promise<Selectable<Verification>[]>;
10
+ create(verifications: Pick<Verification, 'uri' | 'issuer' | 'subject' | 'handle' | 'displayName' | 'createdAt' | 'cid'>[]): Promise<{
11
+ cid: string;
12
+ createdAt: string;
13
+ displayName: string;
14
+ handle: string;
15
+ issuer: string;
16
+ revokeReason: string | null;
17
+ revokedAt: string | null;
18
+ revokedBy: string | null;
19
+ subject: string;
20
+ updatedAt: string;
21
+ uri: string;
22
+ }[]>;
11
23
  markRevoked({ uris, revokedBy, revokedAt, revokeReason, }: {
12
24
  uris: string[];
13
25
  revokedBy?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/verification/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EACL,MAAM,EACN,gBAAgB,EAEhB,wBAAwB,EACxB,0BAA0B,EAC3B,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAE3D,MAAM,MAAM,0BAA0B,GAAG,CAAC,EAAE,EAAE,QAAQ,KAAK,mBAAmB,CAAA;AAE9E,qBAAa,mBAAmB;IACX,EAAE,EAAE,QAAQ;IAA/B,YAAmB,EAAE,EAAE,QAAQ,EAAI;IAEnC,MAAM,CAAC,OAAO,SACA,QAAQ,yBACrB;IAEK,MAAM,CACV,aAAa,EAAE,IAAI,CACjB,YAAY,EACV,KAAK,GACL,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,aAAa,GACb,WAAW,GACX,KAAK,CACR,EAAE,uCAUJ;IAEK,WAAW,CAAC,EAChB,IAAI,EACJ,SAAS,EACT,SAAS,EACT,YAAY,GACb,EAAE;QACD,IAAI,EAAE,MAAM,EAAE,CAAA;QACd,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,wDAkBA;IAEK,IAAI,CAAC,EACT,aAAa,EACb,MAAM,EACN,YAAY,EACZ,aAAa,EACb,OAAY,EACZ,QAAa,EACb,SAAS,EACT,KAAW,GACZ,EAAE;QACD,aAAa,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;QAC9B,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;QAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;QACnB,SAAS,CAAC,EAAE,OAAO,CAAA;QACnB,KAAK,CAAC,EAAE,MAAM,CAAA;KACf;;;;;;;;;;;;;;;OAoCA;IAED,IAAI,CACF,aAAa,EAAE,UAAU,CAAC,YAAY,CAAC,EAAE,EACzC,KAAK,EAAE,GAAG,CACR,MAAM,EACJ,MAAM,CAAC,wBAAwB,CAAC,cAAc,CAAC,GAC/C,MAAM,CAAC,wBAAwB,CAAC,gBAAgB,CAAC,CACpD,EACD,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,GAC1D,MAAM,CAAC,0BAA0B,CAAC,gBAAgB,CAAC,EAAE,CAkCvD;IAEK,iBAAiB,2BAQtB;IAED,oBAAoB,6CASnB;IAEK,oBAAoB,CAAC,MAAM,EAAE,MAAM,sCAYxC;CACF"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/verification/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EACL,MAAM,EACN,gBAAgB,EAEhB,wBAAwB,EACxB,0BAA0B,EAC3B,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAE3D,MAAM,MAAM,0BAA0B,GAAG,CAAC,EAAE,EAAE,QAAQ,KAAK,mBAAmB,CAAA;AAE9E,qBAAa,mBAAmB;IACX,EAAE,EAAE,QAAQ;IAA/B,YAAmB,EAAE,EAAE,QAAQ,EAAI;IAEnC,MAAM,CAAC,OAAO,SACA,QAAQ,yBACrB;IAEK,MAAM,CACV,aAAa,EAAE,IAAI,CACjB,YAAY,EACV,KAAK,GACL,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,aAAa,GACb,WAAW,GACX,KAAK,CACR,EAAE;;;;;;;;;;;;SAUJ;IAEK,WAAW,CAAC,EAChB,IAAI,EACJ,SAAS,EACT,SAAS,EACT,YAAY,GACb,EAAE;QACD,IAAI,EAAE,MAAM,EAAE,CAAA;QACd,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,wDAkBA;IAEK,IAAI,CAAC,EACT,aAAa,EACb,MAAM,EACN,YAAY,EACZ,aAAa,EACb,OAAY,EACZ,QAAa,EACb,SAAS,EACT,KAAW,GACZ,EAAE;QACD,aAAa,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;QAC9B,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;QAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;QACnB,SAAS,CAAC,EAAE,OAAO,CAAA;QACnB,KAAK,CAAC,EAAE,MAAM,CAAA;KACf;;;;;;;;;;;;;;;OAoCA;IAED,IAAI,CACF,aAAa,EAAE,UAAU,CAAC,YAAY,CAAC,EAAE,EACzC,KAAK,EAAE,GAAG,CACR,MAAM,EACJ,MAAM,CAAC,wBAAwB,CAAC,cAAc,CAAC,GAC/C,MAAM,CAAC,wBAAwB,CAAC,gBAAgB,CAAC,CACpD,EACD,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,GAC1D,MAAM,CAAC,0BAA0B,CAAC,gBAAgB,CAAC,EAAE,CAkCvD;IAEK,iBAAiB,2BAQtB;IAED,oBAAoB,6CASnB;IAEK,oBAAoB,CAAC,MAAM,EAAE,MAAM,sCAYxC;CACF"}
@@ -123,7 +123,7 @@ export class VerificationService {
123
123
  .updateTable('firehose_cursor')
124
124
  .set({ cursor })
125
125
  .where('service', '=', 'verification')
126
- .where((qb) => qb.where('cursor', '<', cursor).orWhere('cursor', 'is', null))
126
+ .where((eb) => eb.or([eb('cursor', '<', cursor), eb('cursor', 'is', null)]))
127
127
  .returningAll()
128
128
  .executeTakeFirst();
129
129
  return updated?.cursor;
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/verification/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Selectable } from 'kysely'\nimport {\n $Typed,\n AppBskyActorDefs,\n AtUri,\n ToolsOzoneModerationDefs,\n ToolsOzoneVerificationDefs,\n} from '@atproto/api'\nimport { Database } from '../db/index.js'\nimport { CreatedAtUriKeyset, paginate } from '../db/pagination.js'\nimport { Verification } from '../db/schema/verification.js'\n\nexport type VerificationServiceCreator = (db: Database) => VerificationService\n\nexport class VerificationService {\n constructor(public db: Database) {}\n\n static creator() {\n return (db: Database) => new VerificationService(db)\n }\n\n async create(\n verifications: Pick<\n Verification,\n | 'uri'\n | 'issuer'\n | 'subject'\n | 'handle'\n | 'displayName'\n | 'createdAt'\n | 'cid'\n >[],\n ) {\n return this.db.transaction(async (tx) => {\n return tx.db\n .insertInto('verification')\n .values(verifications)\n .onConflict((oc) => oc.doNothing())\n .returningAll()\n .execute()\n })\n }\n\n async markRevoked({\n uris,\n revokedBy,\n revokedAt,\n revokeReason,\n }: {\n uris: string[]\n revokedBy?: string\n revokedAt?: string\n revokeReason?: string\n }) {\n const now = new Date().toISOString()\n return this.db.transaction(async (tx) => {\n for (const uri of uris) {\n return tx.db\n .updateTable('verification')\n .set({\n revokeReason,\n updatedAt: now,\n revokedAt: revokedAt || now,\n // Allow setting revokedBy to a moderator/verifier DID and if it isn't set, default to the author of the verification record\n revokedBy: revokedBy || new AtUri(uri).host,\n })\n .where('uri', '=', uri)\n .where('revokedAt', 'is', null)\n .execute()\n }\n })\n }\n\n async list({\n sortDirection,\n cursor,\n createdAfter,\n createdBefore,\n issuers = [],\n subjects = [],\n isRevoked,\n limit = 100,\n }: {\n sortDirection?: 'asc' | 'desc'\n cursor?: string\n createdAfter?: string\n createdBefore?: string\n issuers?: string[]\n subjects?: string[]\n isRevoked?: boolean\n limit?: number\n }) {\n const { ref } = this.db.db.dynamic\n\n let qb = this.db.db.selectFrom('verification').selectAll()\n\n if (issuers.length) {\n qb = qb.where('issuer', 'in', issuers)\n }\n\n if (isRevoked !== undefined) {\n qb = qb.where('revokedAt', isRevoked ? 'is not' : 'is', null)\n }\n\n if (subjects.length) {\n qb = qb.where('subject', 'in', subjects)\n }\n\n if (createdAfter) {\n qb = qb.where('createdAt', '>=', createdAfter)\n }\n\n if (createdBefore) {\n qb = qb.where('createdAt', '<=', createdBefore)\n }\n\n const keyset = new CreatedAtUriKeyset(ref(`createdAt`), ref('uri'))\n const paginatedBuilder = paginate(qb, {\n limit,\n cursor,\n keyset,\n tryIndex: true,\n direction: sortDirection === 'desc' ? 'desc' : 'asc',\n })\n\n const result = await paginatedBuilder.execute()\n return { verifications: result, cursor: keyset.packFromResult(result) }\n }\n\n view(\n verifications: Selectable<Verification>[],\n repos: Map<\n string,\n | $Typed<ToolsOzoneModerationDefs.RepoViewDetail>\n | $Typed<ToolsOzoneModerationDefs.RepoViewNotFound>\n >,\n profiles: Map<string, AppBskyActorDefs.ProfileViewDetailed>,\n ): $Typed<ToolsOzoneVerificationDefs.VerificationView>[] {\n return verifications.map((verification) => {\n const issuerRepo = repos.get(verification.issuer)\n const subjectRepo = repos.get(verification.subject)\n const subjectProfile = profiles.get(verification.subject)\n const issuerProfile = profiles.get(verification.issuer)\n return {\n $type: 'tools.ozone.verification.defs#verificationView',\n uri: verification.uri,\n issuer: verification.issuer,\n subject: verification.subject,\n createdAt: verification.createdAt,\n displayName: verification.displayName,\n handle: verification.handle,\n updatedAt: verification.updatedAt || undefined,\n revokedAt: verification.revokedAt || undefined,\n revokedBy: verification.revokedBy || undefined,\n revokeReason: verification.revokeReason || undefined,\n issuerRepo,\n subjectRepo,\n subjectProfile: subjectProfile\n ? {\n $type: 'app.bsky.actor.defs#profileViewDetailed',\n ...subjectProfile,\n }\n : undefined,\n issuerProfile: issuerProfile\n ? {\n $type: 'app.bsky.actor.defs#profileViewDetailed',\n ...issuerProfile,\n }\n : undefined,\n }\n })\n }\n\n async getFirehoseCursor() {\n const entry = await this.db.db\n .selectFrom('firehose_cursor')\n .select('cursor')\n .where('service', '=', 'verification')\n .executeTakeFirst()\n\n return entry?.cursor || null\n }\n\n createFirehoseCursor() {\n return this.db.db\n .insertInto('firehose_cursor')\n .values({\n service: 'verification',\n cursor: null,\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n }\n\n async updateFirehoseCursor(cursor: number) {\n const updated = await this.db.db\n .updateTable('firehose_cursor')\n .set({ cursor })\n .where('service', '=', 'verification')\n .where((qb) =>\n qb.where('cursor', '<', cursor).orWhere('cursor', 'is', null),\n )\n .returningAll()\n .executeTakeFirst()\n\n return updated?.cursor\n }\n}\n"]}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/verification/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Selectable } from 'kysely'\nimport {\n $Typed,\n AppBskyActorDefs,\n AtUri,\n ToolsOzoneModerationDefs,\n ToolsOzoneVerificationDefs,\n} from '@atproto/api'\nimport { Database } from '../db/index.js'\nimport { CreatedAtUriKeyset, paginate } from '../db/pagination.js'\nimport { Verification } from '../db/schema/verification.js'\n\nexport type VerificationServiceCreator = (db: Database) => VerificationService\n\nexport class VerificationService {\n constructor(public db: Database) {}\n\n static creator() {\n return (db: Database) => new VerificationService(db)\n }\n\n async create(\n verifications: Pick<\n Verification,\n | 'uri'\n | 'issuer'\n | 'subject'\n | 'handle'\n | 'displayName'\n | 'createdAt'\n | 'cid'\n >[],\n ) {\n return this.db.transaction(async (tx) => {\n return tx.db\n .insertInto('verification')\n .values(verifications)\n .onConflict((oc) => oc.doNothing())\n .returningAll()\n .execute()\n })\n }\n\n async markRevoked({\n uris,\n revokedBy,\n revokedAt,\n revokeReason,\n }: {\n uris: string[]\n revokedBy?: string\n revokedAt?: string\n revokeReason?: string\n }) {\n const now = new Date().toISOString()\n return this.db.transaction(async (tx) => {\n for (const uri of uris) {\n return tx.db\n .updateTable('verification')\n .set({\n revokeReason,\n updatedAt: now,\n revokedAt: revokedAt || now,\n // Allow setting revokedBy to a moderator/verifier DID and if it isn't set, default to the author of the verification record\n revokedBy: revokedBy || new AtUri(uri).host,\n })\n .where('uri', '=', uri)\n .where('revokedAt', 'is', null)\n .execute()\n }\n })\n }\n\n async list({\n sortDirection,\n cursor,\n createdAfter,\n createdBefore,\n issuers = [],\n subjects = [],\n isRevoked,\n limit = 100,\n }: {\n sortDirection?: 'asc' | 'desc'\n cursor?: string\n createdAfter?: string\n createdBefore?: string\n issuers?: string[]\n subjects?: string[]\n isRevoked?: boolean\n limit?: number\n }) {\n const { ref } = this.db.db.dynamic\n\n let qb = this.db.db.selectFrom('verification').selectAll()\n\n if (issuers.length) {\n qb = qb.where('issuer', 'in', issuers)\n }\n\n if (isRevoked !== undefined) {\n qb = qb.where('revokedAt', isRevoked ? 'is not' : 'is', null)\n }\n\n if (subjects.length) {\n qb = qb.where('subject', 'in', subjects)\n }\n\n if (createdAfter) {\n qb = qb.where('createdAt', '>=', createdAfter)\n }\n\n if (createdBefore) {\n qb = qb.where('createdAt', '<=', createdBefore)\n }\n\n const keyset = new CreatedAtUriKeyset(ref(`createdAt`), ref('uri'))\n const paginatedBuilder = paginate(qb, {\n limit,\n cursor,\n keyset,\n tryIndex: true,\n direction: sortDirection === 'desc' ? 'desc' : 'asc',\n })\n\n const result = await paginatedBuilder.execute()\n return { verifications: result, cursor: keyset.packFromResult(result) }\n }\n\n view(\n verifications: Selectable<Verification>[],\n repos: Map<\n string,\n | $Typed<ToolsOzoneModerationDefs.RepoViewDetail>\n | $Typed<ToolsOzoneModerationDefs.RepoViewNotFound>\n >,\n profiles: Map<string, AppBskyActorDefs.ProfileViewDetailed>,\n ): $Typed<ToolsOzoneVerificationDefs.VerificationView>[] {\n return verifications.map((verification) => {\n const issuerRepo = repos.get(verification.issuer)\n const subjectRepo = repos.get(verification.subject)\n const subjectProfile = profiles.get(verification.subject)\n const issuerProfile = profiles.get(verification.issuer)\n return {\n $type: 'tools.ozone.verification.defs#verificationView',\n uri: verification.uri,\n issuer: verification.issuer,\n subject: verification.subject,\n createdAt: verification.createdAt,\n displayName: verification.displayName,\n handle: verification.handle,\n updatedAt: verification.updatedAt || undefined,\n revokedAt: verification.revokedAt || undefined,\n revokedBy: verification.revokedBy || undefined,\n revokeReason: verification.revokeReason || undefined,\n issuerRepo,\n subjectRepo,\n subjectProfile: subjectProfile\n ? {\n $type: 'app.bsky.actor.defs#profileViewDetailed',\n ...subjectProfile,\n }\n : undefined,\n issuerProfile: issuerProfile\n ? {\n $type: 'app.bsky.actor.defs#profileViewDetailed',\n ...issuerProfile,\n }\n : undefined,\n }\n })\n }\n\n async getFirehoseCursor() {\n const entry = await this.db.db\n .selectFrom('firehose_cursor')\n .select('cursor')\n .where('service', '=', 'verification')\n .executeTakeFirst()\n\n return entry?.cursor || null\n }\n\n createFirehoseCursor() {\n return this.db.db\n .insertInto('firehose_cursor')\n .values({\n service: 'verification',\n cursor: null,\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n }\n\n async updateFirehoseCursor(cursor: number) {\n const updated = await this.db.db\n .updateTable('firehose_cursor')\n .set({ cursor })\n .where('service', '=', 'verification')\n .where((eb) =>\n eb.or([eb('cursor', '<', cursor), eb('cursor', 'is', null)]),\n )\n .returningAll()\n .executeTakeFirst()\n\n return updated?.cursor\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/ozone",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "license": "MIT",
5
5
  "description": "Backend service for moderating the Bluesky network.",
6
6
  "keywords": [
@@ -22,7 +22,7 @@
22
22
  "cors": "^2.8.5",
23
23
  "express": "^4.17.2",
24
24
  "http-terminator": "^3.2.0",
25
- "kysely": "^0.22.0",
25
+ "kysely": "^0.29.2",
26
26
  "lande": "^1.0.10",
27
27
  "multiformats": "^13.0.0",
28
28
  "p-queue": "^8.0.0",
@@ -31,17 +31,17 @@
31
31
  "structured-headers": "^1.0.1",
32
32
  "typed-emitter": "^2.1.0",
33
33
  "uint8arrays": "^5.0.0",
34
- "undici": "^6.14.1",
34
+ "undici": "^8.5.0",
35
35
  "ws": "^8.12.0",
36
- "@atproto/api": "^0.20.16",
37
- "@atproto/common": "^0.6.3",
36
+ "@atproto/api": "^0.20.17",
38
37
  "@atproto/crypto": "^0.5.1",
39
38
  "@atproto/identity": "^0.5.1",
40
- "@atproto/lexicon": "^0.7.2",
41
39
  "@atproto/syntax": "^0.6.2",
42
- "@atproto/ws-client": "^0.1.1",
43
- "@atproto/xrpc-server": "^0.11.2",
44
- "@atproto/xrpc": "^0.8.1"
40
+ "@atproto/ws-client": "^0.1.2",
41
+ "@atproto/xrpc": "^0.8.1",
42
+ "@atproto/common": "^0.6.3",
43
+ "@atproto/lexicon": "^0.7.2",
44
+ "@atproto/xrpc-server": "^0.11.2"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@did-plc/server": "^0.0.1",
@@ -49,12 +49,13 @@
49
49
  "@types/cors": "^2.8.12",
50
50
  "@types/express": "^4.17.13",
51
51
  "@types/express-serve-static-core": "^4.17.36",
52
- "@types/pg": "^8.6.6",
52
+ "@types/pg": "^8.15.5",
53
53
  "@types/qs": "^6.9.7",
54
+ "@types/ws": "^8.18.1",
54
55
  "jest": "^30.0.0",
55
56
  "ts-node": "^10.8.2",
56
57
  "@atproto/lex-cli": "^0.10.1",
57
- "@atproto/pds": "^0.5.5"
58
+ "@atproto/pds": "^0.5.7"
58
59
  },
59
60
  "type": "module",
60
61
  "exports": {
package/src/api/index.ts CHANGED
@@ -41,6 +41,7 @@ import getLatestReport from './report/getLatestReport.js'
41
41
  import getLiveStats from './report/getLiveStats.js'
42
42
  import getReport from './report/getReport.js'
43
43
  import listActivities from './report/listActivities.js'
44
+ import queryActivities from './report/queryActivities.js'
44
45
  import queryReports from './report/queryReports.js'
45
46
  import reassignQueue from './report/reassignQueue.js'
46
47
  import refreshStats from './report/refreshStats.js'
@@ -139,6 +140,7 @@ export default function (server: Server, ctx: AppContext) {
139
140
  getReportAssignments(server, ctx)
140
141
  createActivity(server, ctx)
141
142
  listActivities(server, ctx)
143
+ queryActivities(server, ctx)
142
144
  reassignQueue(server, ctx)
143
145
  return server
144
146
  }
@@ -1,4 +1,3 @@
1
- import { sql } from 'kysely'
2
1
  import { InvalidRequestError } from '@atproto/xrpc-server'
3
2
  import { AppContext } from '../../context.js'
4
3
  import { Server } from '../../lexicon/index.js'
@@ -9,14 +8,13 @@ export default function (server: Server, ctx: AppContext) {
9
8
  let builder = ctx.db.db.selectFrom('label').selectAll().limit(limit)
10
9
  // if includes '*', then we don't need a where clause
11
10
  if (!uriPatterns.includes('*')) {
12
- builder = builder.where((qb) => {
13
- // starter where clause that is always false so that we can chain `orWhere`s
14
- qb = qb.where(sql`1 = 0`)
15
- for (const pattern of uriPatterns) {
16
- // if no '*', then we're looking for an exact match
17
- if (!pattern.includes('*')) {
18
- qb = qb.orWhere('uri', '=', pattern)
19
- } else {
11
+ builder = builder.where((eb) =>
12
+ eb.or(
13
+ uriPatterns.map((pattern) => {
14
+ // if no '*', then we're looking for an exact match
15
+ if (!pattern.includes('*')) {
16
+ return eb('uri', '=', pattern)
17
+ }
20
18
  if (pattern.indexOf('*') < pattern.length - 1) {
21
19
  throw new InvalidRequestError(`invalid pattern: ${pattern}`)
22
20
  }
@@ -24,11 +22,10 @@ export default function (server: Server, ctx: AppContext) {
24
22
  .slice(0, -1)
25
23
  .replaceAll('%', '') // sanitize search pattern
26
24
  .replaceAll('_', '\\_') // escape any underscores
27
- qb = qb.orWhere('uri', 'like', `${searchPattern}%`)
28
- }
29
- }
30
- return qb
31
- })
25
+ return eb('uri', 'like', `${searchPattern}%`)
26
+ }),
27
+ ),
28
+ )
32
29
  }
33
30
  if (sources && sources.length > 0) {
34
31
  builder = builder.where('src', 'in', sources)
@@ -0,0 +1,64 @@
1
+ import { AppContext } from '../../context.js'
2
+ import { Server } from '../../lexicon/index.js'
3
+ import { ReportView } from '../../lexicon/types/tools/ozone/report/defs.js'
4
+ import { getReportsByIds } from '../../mod-service/report.js'
5
+ import {
6
+ formatActivityView,
7
+ queryReportActivities,
8
+ } from '../../report/activity.js'
9
+ import { buildReportView, hydrateReportInfo } from '../../report/views.js'
10
+ import { getPdsAccountInfos } from '../util.js'
11
+
12
+ export default function (server: Server, ctx: AppContext) {
13
+ server.tools.ozone.report.queryActivities({
14
+ auth: ctx.authVerifier.modOrAdminToken,
15
+ handler: async ({ params, auth, req }) => {
16
+ const db = ctx.db
17
+ const modService = ctx.modService(db)
18
+ const labelers = ctx.reqLabelers(req)
19
+
20
+ const { activities, cursor: nextCursor } = await queryReportActivities(
21
+ db,
22
+ params,
23
+ )
24
+
25
+ // Dedupe report IDs across the page. Many activities can share the
26
+ // same report so we want one bulk fetch + hydrate rather than N.
27
+ const reportIds = Array.from(new Set(activities.map((a) => a.reportId)))
28
+
29
+ const queueService = ctx.queueService(db)
30
+ const teamService = ctx.teamService(db)
31
+ const reports = await getReportsByIds(db, reportIds)
32
+ const hydrated = await hydrateReportInfo(
33
+ reports,
34
+ modService.views,
35
+ (dids) => getPdsAccountInfos(ctx, dids),
36
+ (queueIds) => queueService.getViewsByIds(queueIds),
37
+ (dids) => teamService.viewByDids(dids),
38
+ labelers,
39
+ )
40
+ const reportViews = new Map<number, ReportView>()
41
+ for (const report of reports) {
42
+ reportViews.set(
43
+ report.id,
44
+ buildReportView(report, hydrated, auth.credentials.isModerator),
45
+ )
46
+ }
47
+
48
+ const createdByDids = Array.from(
49
+ new Set(activities.map((a) => a.createdBy)),
50
+ )
51
+ const memberViews = await teamService.viewByDids(createdByDids)
52
+
53
+ return {
54
+ encoding: 'application/json',
55
+ body: {
56
+ activities: activities.map((activity) =>
57
+ formatActivityView(activity, memberViews, reportViews),
58
+ ),
59
+ cursor: nextCursor,
60
+ },
61
+ }
62
+ },
63
+ })
64
+ }
@@ -129,8 +129,8 @@ export class AssignmentService {
129
129
 
130
130
  if (onlyActive) {
131
131
  const now = new Date().toISOString()
132
- query = query.where((qb) =>
133
- qb.where('endAt', 'is', null).orWhere('endAt', '>', now),
132
+ query = query.where((eb) =>
133
+ eb.or([eb('endAt', 'is', null), eb('endAt', '>', now)]),
134
134
  )
135
135
  }
136
136
 
@@ -198,8 +198,8 @@ export class AssignmentService {
198
198
 
199
199
  if (onlyActive) {
200
200
  const now = new Date().toISOString()
201
- query = query.where((qb) =>
202
- qb.where('endAt', '>', now).orWhere('endAt', 'is', null),
201
+ query = query.where((eb) =>
202
+ eb.or([eb('endAt', '>', now), eb('endAt', 'is', null)]),
203
203
  )
204
204
  }
205
205
 
@@ -266,10 +266,8 @@ export class AssignmentService {
266
266
  .where('did', '=', did)
267
267
  .where('queueId', '=', queueId)
268
268
  .where('reportId', 'is', null)
269
- .where((qb) =>
270
- qb
271
- .where('endAt', 'is', null)
272
- .orWhere('endAt', '>', now.toISOString()),
269
+ .where((eb) =>
270
+ eb.or([eb('endAt', 'is', null), eb('endAt', '>', now.toISOString())]),
273
271
  )
274
272
  .executeTakeFirst()
275
273
  if (existing) {
@@ -338,8 +336,8 @@ export class AssignmentService {
338
336
  .where('did', '=', did)
339
337
  .where('queueId', '=', queueId)
340
338
  .where('reportId', 'is', null)
341
- .where((qb) =>
342
- qb.where('endAt', 'is', null).orWhere('endAt', '>', now.toISOString()),
339
+ .where((eb) =>
340
+ eb.or([eb('endAt', 'is', null), eb('endAt', '>', now.toISOString())]),
343
341
  )
344
342
  .executeTakeFirst()
345
343
 
@@ -447,10 +445,8 @@ export class AssignmentService {
447
445
  .selectFrom('moderator_assignment')
448
446
  .selectAll()
449
447
  .where('reportId', '=', reportId)
450
- .where((qb) =>
451
- qb
452
- .where('endAt', '>', now.toISOString())
453
- .orWhere('endAt', 'is', null),
448
+ .where((eb) =>
449
+ eb.or([eb('endAt', '>', now.toISOString()), eb('endAt', 'is', null)]),
454
450
  )
455
451
  .executeTakeFirst()
456
452
 
@@ -533,10 +529,11 @@ export class AssignmentService {
533
529
  .selectFrom('moderator_assignment')
534
530
  .selectAll()
535
531
  .where('reportId', '=', reportId)
536
- .where((qb) =>
537
- qb
538
- .where('endAt', '>', now.toISOString())
539
- .orWhere('endAt', 'is', null),
532
+ .where((eb) =>
533
+ eb.or([
534
+ eb('endAt', '>', now.toISOString()),
535
+ eb('endAt', 'is', null),
536
+ ]),
540
537
  )
541
538
  .executeTakeFirst()
542
539
 
package/src/background.ts CHANGED
@@ -9,9 +9,19 @@ import {
9
9
 
10
10
  type Task = (db: Database, signal: AbortSignal) => Promise<void>
11
11
 
12
+ export type BackgroundQueueOptions = NonNullable<
13
+ ConstructorParameters<typeof PQueue>[0]
14
+ > & {
15
+ concurrency: number
16
+ }
17
+
12
18
  /**
13
19
  * A simple queue for in-process, out-of-band/backgrounded work
14
20
  */
21
+ // @NOTE Keep this in sync with the BackgroundQueue in
22
+ // - packages/bsky/src/data-plane/server/background.ts
23
+ // - packages/ozone/src/background.ts
24
+ // - packages/pds/src/background.ts
15
25
  export class BackgroundQueue {
16
26
  private abortController = new AbortController()
17
27
  private queue: PQueue
@@ -26,9 +36,9 @@ export class BackgroundQueue {
26
36
 
27
37
  constructor(
28
38
  protected db: Database,
29
- queueOpts?: { concurrency?: number },
39
+ options: BackgroundQueueOptions,
30
40
  ) {
31
- this.queue = new PQueue(queueOpts ?? { concurrency: 20 })
41
+ this.queue = new PQueue(options)
32
42
  }
33
43
 
34
44
  getStats() {
@@ -76,7 +86,8 @@ export class BackgroundQueue {
76
86
  }
77
87
 
78
88
  async processAll() {
79
- await this.queue.onIdle()
89
+ const { queue } = this
90
+ while (queue.size || queue.pending) await queue.onIdle()
80
91
  }
81
92
 
82
93
  /**
@@ -86,8 +97,12 @@ export class BackgroundQueue {
86
97
  * only once http connections have drained (tasks no longer being added).
87
98
  */
88
99
  async destroy() {
100
+ if (this.destroyed) {
101
+ dbLogger.warn('BackgroundQueue.destroy() called multiple times')
102
+ }
103
+
89
104
  this.abortController.abort()
90
- await this.queue.onIdle()
105
+ return this.processAll()
91
106
  }
92
107
  }
93
108
 
package/src/context.ts CHANGED
@@ -135,7 +135,7 @@ export class AppContext {
135
135
  keypair: signingKey,
136
136
  })
137
137
 
138
- const backgroundQueue = new BackgroundQueue(db)
138
+ const backgroundQueue = new BackgroundQueue(db, { concurrency: 20 })
139
139
  const blobDiverter = cfg.blobDivert
140
140
  ? new BlobDiverter(db, {
141
141
  idResolver,
@@ -73,7 +73,7 @@ export class DaemonContext {
73
73
  pds: cfg.pds ?? undefined,
74
74
  })
75
75
 
76
- const backgroundQueue = new BackgroundQueue(db)
76
+ const backgroundQueue = new BackgroundQueue(db, { concurrency: 20 })
77
77
 
78
78
  const settingService = SettingService.creator()
79
79
  const strikeService = StrikeService.creator()
@@ -156,9 +156,14 @@ export class VerificationListener {
156
156
  })
157
157
  }
158
158
 
159
- stop() {
160
- this.jetstream?.close()
161
- this.backgroundQueue.destroy()
162
- this.destroyed = true
159
+ async stop() {
160
+ if (!this.destroyed) {
161
+ this.destroyed = true
162
+ try {
163
+ await this.jetstream?.close()
164
+ } finally {
165
+ await this.backgroundQueue.destroy()
166
+ }
167
+ }
163
168
  }
164
169
  }
package/src/db/index.ts CHANGED
@@ -3,7 +3,6 @@ import { EventEmitter } from 'node:events'
3
3
  import {
4
4
  Kysely,
5
5
  KyselyPlugin,
6
- Migrator,
7
6
  PluginTransformQueryArgs,
8
7
  PluginTransformResultArgs,
9
8
  PostgresDialect,
@@ -11,6 +10,7 @@ import {
11
10
  RootOperationNode,
12
11
  UnknownRow,
13
12
  } from 'kysely'
13
+ import { Migrator } from 'kysely/migration'
14
14
  // eslint-disable-next-line import/default
15
15
  import pg from 'pg'
16
16
  // eslint-disable-next-line import/no-named-as-default-member
@@ -4,7 +4,6 @@ import {
4
4
  REVIEWESCALATED,
5
5
  REVIEWOPEN,
6
6
  } from '../../lexicon/types/tools/ozone/moderation/defs.js'
7
- import { DatabaseSchemaType } from '../schema/index.js'
8
7
  import * as modEvent from '../schema/moderation_event.js'
9
8
  import * as modStatus from '../schema/moderation_subject_status.js'
10
9
  import * as recordEventsStats from '../schema/record_events_stats.js'
@@ -208,7 +207,7 @@ export async function up(db: Kysely<any>): Promise<void> {
208
207
  .execute()
209
208
  }
210
209
 
211
- export async function down(db: Kysely<DatabaseSchemaType>): Promise<void> {
210
+ export async function down(db: Kysely<any>): Promise<void> {
212
211
  db.schema.dropView('account_record_status_stats').materialized().execute()
213
212
  db.schema.dropView('account_record_events_stats').materialized().execute()
214
213
  db.schema.dropView('record_events_stats').materialized().execute()
@@ -1,7 +1,6 @@
1
1
  import { Kysely, sql } from 'kysely'
2
2
  import { OZONE_APPEAL_REASON_TYPE } from '../../api/util.js'
3
3
  import { REASONAPPEAL } from '../../lexicon/types/com/atproto/moderation/defs.js'
4
- import { DatabaseSchemaType } from '../schema/index.js'
5
4
  import * as modEvent from '../schema/moderation_event.js'
6
5
  import * as recordEventsStats from '../schema/record_events_stats.js'
7
6
 
@@ -161,7 +160,7 @@ export async function up(db: Kysely<any>): Promise<void> {
161
160
  .execute()
162
161
  }
163
162
 
164
- export async function down(db: Kysely<DatabaseSchemaType>): Promise<void> {
163
+ export async function down(db: Kysely<any>): Promise<void> {
165
164
  // Drop the updated materialized views
166
165
  await db.schema
167
166
  .dropView('account_record_events_stats')
@@ -0,0 +1,17 @@
1
+ import { Kysely } from 'kysely'
2
+
3
+ export async function up(db: Kysely<unknown>): Promise<void> {
4
+ // Supports time-ordered scans across all reports for downstream pollers
5
+ // (e.g. Nimbus' report-activity watcher). The existing indexes are all
6
+ // leading-`reportId`, which would force a sequential scan for global
7
+ // ordered queries.
8
+ await db.schema
9
+ .createIndex('idx_report_activity_created')
10
+ .on('report_activity')
11
+ .columns(['createdAt', 'id'])
12
+ .execute()
13
+ }
14
+
15
+ export async function down(db: Kysely<unknown>): Promise<void> {
16
+ await db.schema.dropIndex('idx_report_activity_created').execute()
17
+ }