@atproto/ozone 0.0.2

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 (444) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/LICENSE.txt +7 -0
  3. package/README.md +15 -0
  4. package/babel.config.js +3 -0
  5. package/bin/migration-create.ts +38 -0
  6. package/build.js +18 -0
  7. package/dist/api/admin/emitModerationEvent.d.ts +3 -0
  8. package/dist/api/admin/getModerationEvent.d.ts +3 -0
  9. package/dist/api/admin/getRecord.d.ts +3 -0
  10. package/dist/api/admin/getRepo.d.ts +3 -0
  11. package/dist/api/admin/queryModerationEvents.d.ts +3 -0
  12. package/dist/api/admin/queryModerationStatuses.d.ts +3 -0
  13. package/dist/api/admin/searchRepos.d.ts +3 -0
  14. package/dist/api/admin/util.d.ts +5 -0
  15. package/dist/api/com/atproto/admin/emitModerationEvent.d.ts +3 -0
  16. package/dist/api/com/atproto/admin/getModerationEvent.d.ts +3 -0
  17. package/dist/api/com/atproto/admin/getRecord.d.ts +3 -0
  18. package/dist/api/com/atproto/admin/getRepo.d.ts +3 -0
  19. package/dist/api/com/atproto/admin/queryModerationEvents.d.ts +3 -0
  20. package/dist/api/com/atproto/admin/queryModerationStatuses.d.ts +3 -0
  21. package/dist/api/com/atproto/admin/searchRepos.d.ts +3 -0
  22. package/dist/api/com/atproto/admin/util.d.ts +5 -0
  23. package/dist/api/com/atproto/moderation/createReport.d.ts +3 -0
  24. package/dist/api/com/atproto/moderation/util.d.ts +4 -0
  25. package/dist/api/com/atproto/temp/fetchLabels.d.ts +3 -0
  26. package/dist/api/health.d.ts +3 -0
  27. package/dist/api/index.d.ts +5 -0
  28. package/dist/api/label/queryLabels.d.ts +3 -0
  29. package/dist/api/label/subscribeLabels.d.ts +3 -0
  30. package/dist/api/moderation/createReport.d.ts +3 -0
  31. package/dist/api/moderation/util.d.ts +4 -0
  32. package/dist/api/temp/fetchLabels.d.ts +3 -0
  33. package/dist/api/util.d.ts +2 -0
  34. package/dist/api/well-known.d.ts +3 -0
  35. package/dist/auth-verifier.d.ts +47 -0
  36. package/dist/auth.d.ts +81 -0
  37. package/dist/background.d.ts +13 -0
  38. package/dist/config/config.d.ts +30 -0
  39. package/dist/config/env.d.ts +19 -0
  40. package/dist/config/index.d.ts +3 -0
  41. package/dist/config/secrets.d.ts +8 -0
  42. package/dist/config.d.ts +42 -0
  43. package/dist/context.d.ts +140 -0
  44. package/dist/daemon/config.d.ts +23 -0
  45. package/dist/daemon/context.d.ts +25 -0
  46. package/dist/daemon/event-pusher.d.ts +48 -0
  47. package/dist/daemon/event-reverser.d.ts +16 -0
  48. package/dist/daemon/index.d.ts +13 -0
  49. package/dist/db/index.d.ts +32 -0
  50. package/dist/db/index.js +33707 -0
  51. package/dist/db/index.js.map +7 -0
  52. package/dist/db/migrations/20231219T205730722Z-init.d.ts +3 -0
  53. package/dist/db/migrations/index.d.ts +1 -0
  54. package/dist/db/migrations/provider.d.ts +11 -0
  55. package/dist/db/pagination.d.ts +66 -0
  56. package/dist/db/schema/blob_push_event.d.ts +17 -0
  57. package/dist/db/schema/index.d.ts +10 -0
  58. package/dist/db/schema/label.d.ts +12 -0
  59. package/dist/db/schema/moderation_event.d.ts +22 -0
  60. package/dist/db/schema/moderation_subject_status.d.ts +25 -0
  61. package/dist/db/schema/record_push_event.d.ts +17 -0
  62. package/dist/db/schema/repo_push_event.d.ts +15 -0
  63. package/dist/db/types.d.ts +12 -0
  64. package/dist/error.d.ts +2 -0
  65. package/dist/index.d.ts +27 -0
  66. package/dist/index.js +131818 -0
  67. package/dist/index.js.map +7 -0
  68. package/dist/lexicon/index.d.ts +372 -0
  69. package/dist/lexicon/lexicons.d.ts +7553 -0
  70. package/dist/lexicon/types/app/bsky/actor/defs.d.ts +104 -0
  71. package/dist/lexicon/types/app/bsky/actor/getPreferences.d.ts +31 -0
  72. package/dist/lexicon/types/app/bsky/actor/getProfile.d.ts +29 -0
  73. package/dist/lexicon/types/app/bsky/actor/getProfiles.d.ts +32 -0
  74. package/dist/lexicon/types/app/bsky/actor/getSuggestions.d.ts +34 -0
  75. package/dist/lexicon/types/app/bsky/actor/profile.d.ts +15 -0
  76. package/dist/lexicon/types/app/bsky/actor/putPreferences.d.ts +26 -0
  77. package/dist/lexicon/types/app/bsky/actor/searchActors.d.ts +36 -0
  78. package/dist/lexicon/types/app/bsky/actor/searchActorsTypeahead.d.ts +34 -0
  79. package/dist/lexicon/types/app/bsky/embed/external.d.ts +31 -0
  80. package/dist/lexicon/types/app/bsky/embed/images.d.ts +37 -0
  81. package/dist/lexicon/types/app/bsky/embed/record.d.ts +54 -0
  82. package/dist/lexicon/types/app/bsky/embed/recordWithMedia.d.ts +24 -0
  83. package/dist/lexicon/types/app/bsky/feed/defs.d.ts +151 -0
  84. package/dist/lexicon/types/app/bsky/feed/describeFeedGenerator.d.ts +46 -0
  85. package/dist/lexicon/types/app/bsky/feed/generator.d.ts +18 -0
  86. package/dist/lexicon/types/app/bsky/feed/getActorFeeds.d.ts +35 -0
  87. package/dist/lexicon/types/app/bsky/feed/getActorLikes.d.ts +36 -0
  88. package/dist/lexicon/types/app/bsky/feed/getAuthorFeed.d.ts +37 -0
  89. package/dist/lexicon/types/app/bsky/feed/getFeed.d.ts +36 -0
  90. package/dist/lexicon/types/app/bsky/feed/getFeedGenerator.d.ts +34 -0
  91. package/dist/lexicon/types/app/bsky/feed/getFeedGenerators.d.ts +32 -0
  92. package/dist/lexicon/types/app/bsky/feed/getFeedSkeleton.d.ts +36 -0
  93. package/dist/lexicon/types/app/bsky/feed/getLikes.d.ts +47 -0
  94. package/dist/lexicon/types/app/bsky/feed/getListFeed.d.ts +36 -0
  95. package/dist/lexicon/types/app/bsky/feed/getPostThread.d.ts +38 -0
  96. package/dist/lexicon/types/app/bsky/feed/getPosts.d.ts +32 -0
  97. package/dist/lexicon/types/app/bsky/feed/getRepostedBy.d.ts +38 -0
  98. package/dist/lexicon/types/app/bsky/feed/getSuggestedFeeds.d.ts +34 -0
  99. package/dist/lexicon/types/app/bsky/feed/getTimeline.d.ts +35 -0
  100. package/dist/lexicon/types/app/bsky/feed/like.d.ts +9 -0
  101. package/dist/lexicon/types/app/bsky/feed/post.d.ts +50 -0
  102. package/dist/lexicon/types/app/bsky/feed/repost.d.ts +9 -0
  103. package/dist/lexicon/types/app/bsky/feed/searchPosts.d.ts +37 -0
  104. package/dist/lexicon/types/app/bsky/feed/threadgate.d.ts +28 -0
  105. package/dist/lexicon/types/app/bsky/graph/block.d.ts +8 -0
  106. package/dist/lexicon/types/app/bsky/graph/defs.d.ts +47 -0
  107. package/dist/lexicon/types/app/bsky/graph/follow.d.ts +8 -0
  108. package/dist/lexicon/types/app/bsky/graph/getBlocks.d.ts +34 -0
  109. package/dist/lexicon/types/app/bsky/graph/getFollowers.d.ts +36 -0
  110. package/dist/lexicon/types/app/bsky/graph/getFollows.d.ts +36 -0
  111. package/dist/lexicon/types/app/bsky/graph/getList.d.ts +36 -0
  112. package/dist/lexicon/types/app/bsky/graph/getListBlocks.d.ts +34 -0
  113. package/dist/lexicon/types/app/bsky/graph/getListMutes.d.ts +34 -0
  114. package/dist/lexicon/types/app/bsky/graph/getLists.d.ts +35 -0
  115. package/dist/lexicon/types/app/bsky/graph/getMutes.d.ts +34 -0
  116. package/dist/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.d.ts +32 -0
  117. package/dist/lexicon/types/app/bsky/graph/list.d.ts +19 -0
  118. package/dist/lexicon/types/app/bsky/graph/listblock.d.ts +8 -0
  119. package/dist/lexicon/types/app/bsky/graph/listitem.d.ts +9 -0
  120. package/dist/lexicon/types/app/bsky/graph/muteActor.d.ts +25 -0
  121. package/dist/lexicon/types/app/bsky/graph/muteActorList.d.ts +25 -0
  122. package/dist/lexicon/types/app/bsky/graph/unmuteActor.d.ts +25 -0
  123. package/dist/lexicon/types/app/bsky/graph/unmuteActorList.d.ts +25 -0
  124. package/dist/lexicon/types/app/bsky/moderation/defs.d.ts +49 -0
  125. package/dist/lexicon/types/app/bsky/moderation/getService.d.ts +29 -0
  126. package/dist/lexicon/types/app/bsky/moderation/getServices.d.ts +32 -0
  127. package/dist/lexicon/types/app/bsky/moderation/service.d.ts +17 -0
  128. package/dist/lexicon/types/app/bsky/notification/getUnreadCount.d.ts +31 -0
  129. package/dist/lexicon/types/app/bsky/notification/listNotifications.d.ts +52 -0
  130. package/dist/lexicon/types/app/bsky/notification/registerPush.d.ts +28 -0
  131. package/dist/lexicon/types/app/bsky/notification/updateSeen.d.ts +25 -0
  132. package/dist/lexicon/types/app/bsky/richtext/facet.d.ts +36 -0
  133. package/dist/lexicon/types/app/bsky/unspecced/defs.d.ts +13 -0
  134. package/dist/lexicon/types/app/bsky/unspecced/getPopular.d.ts +35 -0
  135. package/dist/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.d.ts +35 -0
  136. package/dist/lexicon/types/app/bsky/unspecced/getTimelineSkeleton.d.ts +35 -0
  137. package/dist/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.d.ts +38 -0
  138. package/dist/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.d.ts +37 -0
  139. package/dist/lexicon/types/com/atproto/admin/defs.d.ts +319 -0
  140. package/dist/lexicon/types/com/atproto/admin/deleteAccount.d.ts +25 -0
  141. package/dist/lexicon/types/com/atproto/admin/disableAccountInvites.d.ts +26 -0
  142. package/dist/lexicon/types/com/atproto/admin/disableInviteCodes.d.ts +26 -0
  143. package/dist/lexicon/types/com/atproto/admin/emitModerationEvent.d.ts +45 -0
  144. package/dist/lexicon/types/com/atproto/admin/enableAccountInvites.d.ts +26 -0
  145. package/dist/lexicon/types/com/atproto/admin/getAccountInfo.d.ts +29 -0
  146. package/dist/lexicon/types/com/atproto/admin/getAccountInfos.d.ts +32 -0
  147. package/dist/lexicon/types/com/atproto/admin/getInviteCodes.d.ts +35 -0
  148. package/dist/lexicon/types/com/atproto/admin/getModerationEvent.d.ts +29 -0
  149. package/dist/lexicon/types/com/atproto/admin/getRecord.d.ts +31 -0
  150. package/dist/lexicon/types/com/atproto/admin/getRepo.d.ts +30 -0
  151. package/dist/lexicon/types/com/atproto/admin/getSubjectStatus.d.ts +39 -0
  152. package/dist/lexicon/types/com/atproto/admin/queryModerationEvents.d.ts +39 -0
  153. package/dist/lexicon/types/com/atproto/admin/queryModerationStatuses.d.ts +48 -0
  154. package/dist/lexicon/types/com/atproto/admin/searchRepos.d.ts +36 -0
  155. package/dist/lexicon/types/com/atproto/admin/sendEmail.d.ts +40 -0
  156. package/dist/lexicon/types/com/atproto/admin/updateAccountEmail.d.ts +26 -0
  157. package/dist/lexicon/types/com/atproto/admin/updateAccountHandle.d.ts +26 -0
  158. package/dist/lexicon/types/com/atproto/admin/updateSubjectStatus.d.ts +46 -0
  159. package/dist/lexicon/types/com/atproto/identity/resolveHandle.d.ts +31 -0
  160. package/dist/lexicon/types/com/atproto/identity/updateHandle.d.ts +25 -0
  161. package/dist/lexicon/types/com/atproto/label/defs.d.ts +24 -0
  162. package/dist/lexicon/types/com/atproto/label/queryLabels.d.ts +36 -0
  163. package/dist/lexicon/types/com/atproto/label/subscribeLabels.d.ts +36 -0
  164. package/dist/lexicon/types/com/atproto/moderation/createReport.d.ts +52 -0
  165. package/dist/lexicon/types/com/atproto/moderation/defs.d.ts +8 -0
  166. package/dist/lexicon/types/com/atproto/repo/applyWrites.d.ts +53 -0
  167. package/dist/lexicon/types/com/atproto/repo/createRecord.d.ts +43 -0
  168. package/dist/lexicon/types/com/atproto/repo/deleteRecord.d.ts +30 -0
  169. package/dist/lexicon/types/com/atproto/repo/describeRepo.d.ts +35 -0
  170. package/dist/lexicon/types/com/atproto/repo/getRecord.d.ts +36 -0
  171. package/dist/lexicon/types/com/atproto/repo/listRecords.d.ts +47 -0
  172. package/dist/lexicon/types/com/atproto/repo/putRecord.d.ts +44 -0
  173. package/dist/lexicon/types/com/atproto/repo/strongRef.d.ts +8 -0
  174. package/dist/lexicon/types/com/atproto/repo/uploadBlob.d.ts +36 -0
  175. package/dist/lexicon/types/com/atproto/server/confirmEmail.d.ts +27 -0
  176. package/dist/lexicon/types/com/atproto/server/createAccount.d.ts +49 -0
  177. package/dist/lexicon/types/com/atproto/server/createAppPassword.d.ts +43 -0
  178. package/dist/lexicon/types/com/atproto/server/createInviteCode.d.ts +37 -0
  179. package/dist/lexicon/types/com/atproto/server/createInviteCodes.d.ts +46 -0
  180. package/dist/lexicon/types/com/atproto/server/createSession.d.ts +44 -0
  181. package/dist/lexicon/types/com/atproto/server/defs.d.ts +20 -0
  182. package/dist/lexicon/types/com/atproto/server/deleteAccount.d.ts +28 -0
  183. package/dist/lexicon/types/com/atproto/server/deleteSession.d.ts +19 -0
  184. package/dist/lexicon/types/com/atproto/server/describeServer.d.ts +41 -0
  185. package/dist/lexicon/types/com/atproto/server/getAccountInviteCodes.d.ts +34 -0
  186. package/dist/lexicon/types/com/atproto/server/getSession.d.ts +34 -0
  187. package/dist/lexicon/types/com/atproto/server/listAppPasswords.d.ts +39 -0
  188. package/dist/lexicon/types/com/atproto/server/refreshSession.d.ts +35 -0
  189. package/dist/lexicon/types/com/atproto/server/requestAccountDelete.d.ts +19 -0
  190. package/dist/lexicon/types/com/atproto/server/requestEmailConfirmation.d.ts +19 -0
  191. package/dist/lexicon/types/com/atproto/server/requestEmailUpdate.d.ts +30 -0
  192. package/dist/lexicon/types/com/atproto/server/requestPasswordReset.d.ts +25 -0
  193. package/dist/lexicon/types/com/atproto/server/reserveSigningKey.d.ts +36 -0
  194. package/dist/lexicon/types/com/atproto/server/resetPassword.d.ts +27 -0
  195. package/dist/lexicon/types/com/atproto/server/revokeAppPassword.d.ts +25 -0
  196. package/dist/lexicon/types/com/atproto/server/updateEmail.d.ts +27 -0
  197. package/dist/lexicon/types/com/atproto/sync/getBlob.d.ts +30 -0
  198. package/dist/lexicon/types/com/atproto/sync/getBlocks.d.ts +30 -0
  199. package/dist/lexicon/types/com/atproto/sync/getCheckout.d.ts +29 -0
  200. package/dist/lexicon/types/com/atproto/sync/getHead.d.ts +32 -0
  201. package/dist/lexicon/types/com/atproto/sync/getLatestCommit.d.ts +33 -0
  202. package/dist/lexicon/types/com/atproto/sync/getRecord.d.ts +32 -0
  203. package/dist/lexicon/types/com/atproto/sync/getRepo.d.ts +30 -0
  204. package/dist/lexicon/types/com/atproto/sync/listBlobs.d.ts +35 -0
  205. package/dist/lexicon/types/com/atproto/sync/listRepos.d.ts +42 -0
  206. package/dist/lexicon/types/com/atproto/sync/notifyOfUpdate.d.ts +25 -0
  207. package/dist/lexicon/types/com/atproto/sync/requestCrawl.d.ts +25 -0
  208. package/dist/lexicon/types/com/atproto/sync/subscribeRepos.d.ts +80 -0
  209. package/dist/lexicon/types/com/atproto/temp/fetchLabels.d.ts +33 -0
  210. package/dist/lexicon/types/com/atproto/temp/importRepo.d.ts +32 -0
  211. package/dist/lexicon/types/com/atproto/temp/pushBlob.d.ts +25 -0
  212. package/dist/lexicon/types/com/atproto/temp/requestPhoneVerification.d.ts +25 -0
  213. package/dist/lexicon/types/com/atproto/temp/transferAccount.d.ts +42 -0
  214. package/dist/lexicon/util.d.ts +2 -0
  215. package/dist/logger.d.ts +4 -0
  216. package/dist/mod-service/index.d.ts +155 -0
  217. package/dist/mod-service/status.d.ts +12 -0
  218. package/dist/mod-service/subject.d.ts +59 -0
  219. package/dist/mod-service/types.d.ts +19 -0
  220. package/dist/mod-service/views.d.ts +49 -0
  221. package/dist/sequencer/index.d.ts +2 -0
  222. package/dist/sequencer/outbox.d.ts +16 -0
  223. package/dist/sequencer/sequencer.d.ts +35 -0
  224. package/dist/services/index.d.ts +7 -0
  225. package/dist/services/moderation/index.d.ts +144 -0
  226. package/dist/services/moderation/status.d.ts +12 -0
  227. package/dist/services/moderation/subject.d.ts +60 -0
  228. package/dist/services/moderation/types.d.ts +19 -0
  229. package/dist/services/moderation/views.d.ts +42 -0
  230. package/dist/services/types.d.ts +2 -0
  231. package/dist/util/date.d.ts +1 -0
  232. package/dist/util/debug.d.ts +1 -0
  233. package/dist/util/retry.d.ts +3 -0
  234. package/dist/util.d.ts +3 -0
  235. package/jest.config.js +6 -0
  236. package/package.json +67 -0
  237. package/src/api/admin/emitModerationEvent.ts +130 -0
  238. package/src/api/admin/getModerationEvent.ts +19 -0
  239. package/src/api/admin/getRecord.ts +34 -0
  240. package/src/api/admin/getRepo.ts +31 -0
  241. package/src/api/admin/queryModerationEvents.ts +40 -0
  242. package/src/api/admin/queryModerationStatuses.ts +57 -0
  243. package/src/api/admin/searchRepos.ts +42 -0
  244. package/src/api/admin/util.ts +54 -0
  245. package/src/api/health.ts +20 -0
  246. package/src/api/index.ts +28 -0
  247. package/src/api/moderation/createReport.ts +41 -0
  248. package/src/api/moderation/util.ts +65 -0
  249. package/src/api/temp/fetchLabels.ts +29 -0
  250. package/src/api/well-known.ts +35 -0
  251. package/src/auth.ts +147 -0
  252. package/src/background.ts +35 -0
  253. package/src/config/config.ts +84 -0
  254. package/src/config/env.ts +41 -0
  255. package/src/config/index.ts +3 -0
  256. package/src/config/secrets.ts +23 -0
  257. package/src/context.ts +180 -0
  258. package/src/daemon/context.ts +90 -0
  259. package/src/daemon/event-pusher.ts +296 -0
  260. package/src/daemon/event-reverser.ts +74 -0
  261. package/src/daemon/index.ts +33 -0
  262. package/src/db/index.ts +197 -0
  263. package/src/db/migrations/20231219T205730722Z-init.ts +164 -0
  264. package/src/db/migrations/index.ts +5 -0
  265. package/src/db/migrations/provider.ts +25 -0
  266. package/src/db/pagination.ts +216 -0
  267. package/src/db/schema/blob_push_event.ts +21 -0
  268. package/src/db/schema/index.ts +18 -0
  269. package/src/db/schema/label.ts +12 -0
  270. package/src/db/schema/moderation_event.ts +35 -0
  271. package/src/db/schema/moderation_subject_status.ts +32 -0
  272. package/src/db/schema/record_push_event.ts +21 -0
  273. package/src/db/schema/repo_push_event.ts +19 -0
  274. package/src/db/types.ts +15 -0
  275. package/src/error.ts +12 -0
  276. package/src/index.ts +102 -0
  277. package/src/lexicon/index.ts +1626 -0
  278. package/src/lexicon/lexicons.ts +8050 -0
  279. package/src/lexicon/types/app/bsky/actor/defs.ts +235 -0
  280. package/src/lexicon/types/app/bsky/actor/getPreferences.ts +44 -0
  281. package/src/lexicon/types/app/bsky/actor/getProfile.ts +41 -0
  282. package/src/lexicon/types/app/bsky/actor/getProfiles.ts +46 -0
  283. package/src/lexicon/types/app/bsky/actor/getSuggestions.ts +48 -0
  284. package/src/lexicon/types/app/bsky/actor/profile.ts +32 -0
  285. package/src/lexicon/types/app/bsky/actor/putPreferences.ts +39 -0
  286. package/src/lexicon/types/app/bsky/actor/searchActors.ts +52 -0
  287. package/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts +50 -0
  288. package/src/lexicon/types/app/bsky/embed/external.ts +82 -0
  289. package/src/lexicon/types/app/bsky/embed/images.ts +96 -0
  290. package/src/lexicon/types/app/bsky/embed/record.ts +120 -0
  291. package/src/lexicon/types/app/bsky/embed/recordWithMedia.ts +53 -0
  292. package/src/lexicon/types/app/bsky/feed/defs.ts +308 -0
  293. package/src/lexicon/types/app/bsky/feed/describeFeedGenerator.ts +80 -0
  294. package/src/lexicon/types/app/bsky/feed/generator.ts +35 -0
  295. package/src/lexicon/types/app/bsky/feed/getActorFeeds.ts +49 -0
  296. package/src/lexicon/types/app/bsky/feed/getActorLikes.ts +50 -0
  297. package/src/lexicon/types/app/bsky/feed/getAuthorFeed.ts +56 -0
  298. package/src/lexicon/types/app/bsky/feed/getFeed.ts +50 -0
  299. package/src/lexicon/types/app/bsky/feed/getFeedGenerator.ts +48 -0
  300. package/src/lexicon/types/app/bsky/feed/getFeedGenerators.ts +46 -0
  301. package/src/lexicon/types/app/bsky/feed/getFeedSkeleton.ts +50 -0
  302. package/src/lexicon/types/app/bsky/feed/getLikes.ts +69 -0
  303. package/src/lexicon/types/app/bsky/feed/getListFeed.ts +50 -0
  304. package/src/lexicon/types/app/bsky/feed/getPostThread.ts +53 -0
  305. package/src/lexicon/types/app/bsky/feed/getPosts.ts +46 -0
  306. package/src/lexicon/types/app/bsky/feed/getRepostedBy.ts +52 -0
  307. package/src/lexicon/types/app/bsky/feed/getSuggestedFeeds.ts +48 -0
  308. package/src/lexicon/types/app/bsky/feed/getTimeline.ts +49 -0
  309. package/src/lexicon/types/app/bsky/feed/like.ts +26 -0
  310. package/src/lexicon/types/app/bsky/feed/post.ts +102 -0
  311. package/src/lexicon/types/app/bsky/feed/repost.ts +27 -0
  312. package/src/lexicon/types/app/bsky/feed/searchPosts.ts +54 -0
  313. package/src/lexicon/types/app/bsky/feed/threadgate.ts +84 -0
  314. package/src/lexicon/types/app/bsky/graph/block.ts +26 -0
  315. package/src/lexicon/types/app/bsky/graph/defs.ts +104 -0
  316. package/src/lexicon/types/app/bsky/graph/follow.ts +26 -0
  317. package/src/lexicon/types/app/bsky/graph/getBlocks.ts +48 -0
  318. package/src/lexicon/types/app/bsky/graph/getFollowers.ts +50 -0
  319. package/src/lexicon/types/app/bsky/graph/getFollows.ts +50 -0
  320. package/src/lexicon/types/app/bsky/graph/getList.ts +50 -0
  321. package/src/lexicon/types/app/bsky/graph/getListBlocks.ts +48 -0
  322. package/src/lexicon/types/app/bsky/graph/getListMutes.ts +48 -0
  323. package/src/lexicon/types/app/bsky/graph/getLists.ts +49 -0
  324. package/src/lexicon/types/app/bsky/graph/getMutes.ts +48 -0
  325. package/src/lexicon/types/app/bsky/graph/getSuggestedFollowsByActor.ts +46 -0
  326. package/src/lexicon/types/app/bsky/graph/list.ts +36 -0
  327. package/src/lexicon/types/app/bsky/graph/listblock.ts +26 -0
  328. package/src/lexicon/types/app/bsky/graph/listitem.ts +27 -0
  329. package/src/lexicon/types/app/bsky/graph/muteActor.ts +38 -0
  330. package/src/lexicon/types/app/bsky/graph/muteActorList.ts +38 -0
  331. package/src/lexicon/types/app/bsky/graph/unmuteActor.ts +38 -0
  332. package/src/lexicon/types/app/bsky/graph/unmuteActorList.ts +38 -0
  333. package/src/lexicon/types/app/bsky/notification/getUnreadCount.ts +45 -0
  334. package/src/lexicon/types/app/bsky/notification/listNotifications.ts +87 -0
  335. package/src/lexicon/types/app/bsky/notification/registerPush.ts +41 -0
  336. package/src/lexicon/types/app/bsky/notification/updateSeen.ts +38 -0
  337. package/src/lexicon/types/app/bsky/richtext/facet.ts +97 -0
  338. package/src/lexicon/types/app/bsky/unspecced/defs.ts +41 -0
  339. package/src/lexicon/types/app/bsky/unspecced/getPopularFeedGenerators.ts +49 -0
  340. package/src/lexicon/types/app/bsky/unspecced/getTimelineSkeleton.ts +49 -0
  341. package/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts +56 -0
  342. package/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts +54 -0
  343. package/src/lexicon/types/com/atproto/admin/defs.ts +719 -0
  344. package/src/lexicon/types/com/atproto/admin/deleteAccount.ts +38 -0
  345. package/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts +40 -0
  346. package/src/lexicon/types/com/atproto/admin/disableInviteCodes.ts +39 -0
  347. package/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts +66 -0
  348. package/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts +40 -0
  349. package/src/lexicon/types/com/atproto/admin/getAccountInfo.ts +41 -0
  350. package/src/lexicon/types/com/atproto/admin/getAccountInfos.ts +46 -0
  351. package/src/lexicon/types/com/atproto/admin/getInviteCodes.ts +49 -0
  352. package/src/lexicon/types/com/atproto/admin/getModerationEvent.ts +41 -0
  353. package/src/lexicon/types/com/atproto/admin/getRecord.ts +43 -0
  354. package/src/lexicon/types/com/atproto/admin/getRepo.ts +42 -0
  355. package/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts +54 -0
  356. package/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts +56 -0
  357. package/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts +72 -0
  358. package/src/lexicon/types/com/atproto/admin/searchRepos.ts +51 -0
  359. package/src/lexicon/types/com/atproto/admin/sendEmail.ts +54 -0
  360. package/src/lexicon/types/com/atproto/admin/updateAccountEmail.ts +40 -0
  361. package/src/lexicon/types/com/atproto/admin/updateAccountHandle.ts +39 -0
  362. package/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts +61 -0
  363. package/src/lexicon/types/com/atproto/identity/resolveHandle.ts +46 -0
  364. package/src/lexicon/types/com/atproto/identity/updateHandle.ts +38 -0
  365. package/src/lexicon/types/com/atproto/label/defs.ts +73 -0
  366. package/src/lexicon/types/com/atproto/label/queryLabels.ts +52 -0
  367. package/src/lexicon/types/com/atproto/label/subscribeLabels.ts +67 -0
  368. package/src/lexicon/types/com/atproto/moderation/createReport.ts +65 -0
  369. package/src/lexicon/types/com/atproto/moderation/defs.ts +32 -0
  370. package/src/lexicon/types/com/atproto/repo/applyWrites.ts +103 -0
  371. package/src/lexicon/types/com/atproto/repo/createRecord.ts +62 -0
  372. package/src/lexicon/types/com/atproto/repo/deleteRecord.ts +48 -0
  373. package/src/lexicon/types/com/atproto/repo/describeRepo.ts +50 -0
  374. package/src/lexicon/types/com/atproto/repo/getRecord.ts +54 -0
  375. package/src/lexicon/types/com/atproto/repo/listRecords.ts +77 -0
  376. package/src/lexicon/types/com/atproto/repo/putRecord.ts +64 -0
  377. package/src/lexicon/types/com/atproto/repo/strongRef.ts +26 -0
  378. package/src/lexicon/types/com/atproto/repo/uploadBlob.ts +47 -0
  379. package/src/lexicon/types/com/atproto/server/confirmEmail.ts +40 -0
  380. package/src/lexicon/types/com/atproto/server/createAccount.ts +69 -0
  381. package/src/lexicon/types/com/atproto/server/createAppPassword.ts +69 -0
  382. package/src/lexicon/types/com/atproto/server/createInviteCode.ts +50 -0
  383. package/src/lexicon/types/com/atproto/server/createInviteCodes.ts +72 -0
  384. package/src/lexicon/types/com/atproto/server/createSession.ts +58 -0
  385. package/src/lexicon/types/com/atproto/server/defs.ts +48 -0
  386. package/src/lexicon/types/com/atproto/server/deleteAccount.ts +41 -0
  387. package/src/lexicon/types/com/atproto/server/deleteSession.ts +31 -0
  388. package/src/lexicon/types/com/atproto/server/describeServer.ts +64 -0
  389. package/src/lexicon/types/com/atproto/server/getAccountInviteCodes.ts +48 -0
  390. package/src/lexicon/types/com/atproto/server/getSession.ts +47 -0
  391. package/src/lexicon/types/com/atproto/server/listAppPasswords.ts +62 -0
  392. package/src/lexicon/types/com/atproto/server/refreshSession.ts +48 -0
  393. package/src/lexicon/types/com/atproto/server/requestAccountDelete.ts +31 -0
  394. package/src/lexicon/types/com/atproto/server/requestEmailConfirmation.ts +31 -0
  395. package/src/lexicon/types/com/atproto/server/requestEmailUpdate.ts +43 -0
  396. package/src/lexicon/types/com/atproto/server/requestPasswordReset.ts +38 -0
  397. package/src/lexicon/types/com/atproto/server/reserveSigningKey.ts +51 -0
  398. package/src/lexicon/types/com/atproto/server/resetPassword.ts +40 -0
  399. package/src/lexicon/types/com/atproto/server/revokeAppPassword.ts +38 -0
  400. package/src/lexicon/types/com/atproto/server/updateEmail.ts +41 -0
  401. package/src/lexicon/types/com/atproto/sync/getBlob.ts +43 -0
  402. package/src/lexicon/types/com/atproto/sync/getBlocks.ts +42 -0
  403. package/src/lexicon/types/com/atproto/sync/getCheckout.ts +41 -0
  404. package/src/lexicon/types/com/atproto/sync/getHead.ts +47 -0
  405. package/src/lexicon/types/com/atproto/sync/getLatestCommit.ts +48 -0
  406. package/src/lexicon/types/com/atproto/sync/getRecord.ts +45 -0
  407. package/src/lexicon/types/com/atproto/sync/getRepo.ts +43 -0
  408. package/src/lexicon/types/com/atproto/sync/listBlobs.ts +51 -0
  409. package/src/lexicon/types/com/atproto/sync/listRepos.ts +66 -0
  410. package/src/lexicon/types/com/atproto/sync/notifyOfUpdate.ts +39 -0
  411. package/src/lexicon/types/com/atproto/sync/requestCrawl.ts +39 -0
  412. package/src/lexicon/types/com/atproto/sync/subscribeRepos.ts +161 -0
  413. package/src/lexicon/types/com/atproto/temp/fetchLabels.ts +47 -0
  414. package/src/lexicon/types/com/atproto/temp/importRepo.ts +45 -0
  415. package/src/lexicon/types/com/atproto/temp/pushBlob.ts +39 -0
  416. package/src/lexicon/types/com/atproto/temp/requestPhoneVerification.ts +38 -0
  417. package/src/lexicon/types/com/atproto/temp/transferAccount.ts +62 -0
  418. package/src/lexicon/util.ts +13 -0
  419. package/src/logger.ts +19 -0
  420. package/src/mod-service/index.ts +758 -0
  421. package/src/mod-service/status.ts +264 -0
  422. package/src/mod-service/subject.ts +136 -0
  423. package/src/mod-service/types.ts +32 -0
  424. package/src/mod-service/views.ts +531 -0
  425. package/src/util.ts +26 -0
  426. package/test.env +2 -0
  427. package/test.log +0 -0
  428. package/tests/__snapshots__/get-record.test.ts.snap +173 -0
  429. package/tests/__snapshots__/get-repo.test.ts.snap +57 -0
  430. package/tests/__snapshots__/moderation-events.test.ts.snap +168 -0
  431. package/tests/__snapshots__/moderation-statuses.test.ts.snap +64 -0
  432. package/tests/__snapshots__/moderation.test.ts.snap +55 -0
  433. package/tests/_util.ts +192 -0
  434. package/tests/db.test.ts +184 -0
  435. package/tests/get-record.test.ts +110 -0
  436. package/tests/get-repo.test.ts +131 -0
  437. package/tests/moderation-appeals.test.ts +269 -0
  438. package/tests/moderation-events.test.ts +220 -0
  439. package/tests/moderation-statuses.test.ts +144 -0
  440. package/tests/moderation.test.ts +961 -0
  441. package/tests/repo-search.test.ts +123 -0
  442. package/tests/server.test.ts +76 -0
  443. package/tsconfig.build.json +4 -0
  444. package/tsconfig.json +21 -0
@@ -0,0 +1,197 @@
1
+ import assert from 'assert'
2
+ import {
3
+ Kysely,
4
+ PostgresDialect,
5
+ Migrator,
6
+ KyselyPlugin,
7
+ PluginTransformQueryArgs,
8
+ PluginTransformResultArgs,
9
+ RootOperationNode,
10
+ QueryResult,
11
+ UnknownRow,
12
+ } from 'kysely'
13
+ import TypedEmitter from 'typed-emitter'
14
+ import { Pool as PgPool, types as pgTypes } from 'pg'
15
+ import DatabaseSchema, { DatabaseSchemaType } from './schema'
16
+ import { PgOptions } from './types'
17
+ import { dbLogger } from '../logger'
18
+ import { EventEmitter } from 'stream'
19
+ import * as migrations from './migrations'
20
+ import { CtxMigrationProvider } from './migrations/provider'
21
+
22
+ export class Database {
23
+ pool: PgPool
24
+ db: DatabaseSchema
25
+ migrator: Migrator
26
+ txEvt = new EventEmitter() as TxnEmitter
27
+ destroyed = false
28
+ isPrimary = false
29
+
30
+ constructor(
31
+ public opts: PgOptions,
32
+ instances?: { db: DatabaseSchema; pool: PgPool },
33
+ ) {
34
+ // if instances are provided, use those
35
+ if (instances) {
36
+ this.db = instances.db
37
+ this.pool = instances.pool
38
+ return
39
+ }
40
+
41
+ // else create a pool & connect
42
+ const { schema, url } = opts
43
+ const pool =
44
+ opts.pool ??
45
+ new PgPool({
46
+ connectionString: url,
47
+ max: opts.poolSize,
48
+ maxUses: opts.poolMaxUses,
49
+ idleTimeoutMillis: opts.poolIdleTimeoutMs,
50
+ })
51
+
52
+ // Select count(*) and other pg bigints as js integer
53
+ pgTypes.setTypeParser(pgTypes.builtins.INT8, (n) => parseInt(n, 10))
54
+
55
+ // Setup schema usage, primarily for test parallelism (each test suite runs in its own pg schema)
56
+ if (schema && !/^[a-z_]+$/i.test(schema)) {
57
+ throw new Error(`Postgres schema must only contain [A-Za-z_]: ${schema}`)
58
+ }
59
+
60
+ pool.on('error', onPoolError)
61
+ pool.on('connect', (client) => {
62
+ client.on('error', onClientError)
63
+ // Used for trigram indexes, e.g. on actor search
64
+ client.query('SET pg_trgm.word_similarity_threshold TO .4;')
65
+ if (schema) {
66
+ // Shared objects such as extensions will go in the public schema
67
+ client.query(`SET search_path TO "${schema}",public;`)
68
+ }
69
+ })
70
+
71
+ this.pool = pool
72
+ this.db = new Kysely<DatabaseSchemaType>({
73
+ dialect: new PostgresDialect({ pool }),
74
+ })
75
+ this.migrator = new Migrator({
76
+ db: this.db,
77
+ migrationTableSchema: opts.schema,
78
+ provider: new CtxMigrationProvider(migrations, 'pg'),
79
+ })
80
+ }
81
+
82
+ get schema(): string | undefined {
83
+ return this.opts.schema
84
+ }
85
+
86
+ get isTransaction() {
87
+ return this.db.isTransaction
88
+ }
89
+
90
+ assertTransaction() {
91
+ assert(this.isTransaction, 'Transaction required')
92
+ }
93
+
94
+ assertNotTransaction() {
95
+ assert(!this.isTransaction, 'Cannot be in a transaction')
96
+ }
97
+
98
+ async transaction<T>(fn: (db: Database) => Promise<T>): Promise<T> {
99
+ const leakyTxPlugin = new LeakyTxPlugin()
100
+ const { dbTxn, txRes } = await this.db
101
+ .withPlugin(leakyTxPlugin)
102
+ .transaction()
103
+ .execute(async (txn) => {
104
+ const dbTxn = new Database(this.opts, {
105
+ db: txn,
106
+ pool: this.pool,
107
+ })
108
+ const txRes = await fn(dbTxn)
109
+ .catch(async (err) => {
110
+ leakyTxPlugin.endTx()
111
+ // ensure that all in-flight queries are flushed & the connection is open
112
+ await dbTxn.db.getExecutor().provideConnection(noopAsync)
113
+ throw err
114
+ })
115
+ .finally(() => leakyTxPlugin.endTx())
116
+ return { dbTxn, txRes }
117
+ })
118
+ dbTxn?.txEvt.emit('commit')
119
+ return txRes
120
+ }
121
+
122
+ onCommit(fn: () => void) {
123
+ this.assertTransaction()
124
+ this.txEvt.once('commit', fn)
125
+ }
126
+
127
+ async close(): Promise<void> {
128
+ if (this.destroyed) return
129
+ await this.db.destroy()
130
+ this.destroyed = true
131
+ }
132
+
133
+ async migrateToOrThrow(migration: string) {
134
+ if (this.schema) {
135
+ await this.db.schema.createSchema(this.schema).ifNotExists().execute()
136
+ }
137
+ const { error, results } = await this.migrator.migrateTo(migration)
138
+ if (error) {
139
+ throw error
140
+ }
141
+ if (!results) {
142
+ throw new Error('An unknown failure occurred while migrating')
143
+ }
144
+ return results
145
+ }
146
+
147
+ async migrateToLatestOrThrow() {
148
+ if (this.schema) {
149
+ await this.db.schema.createSchema(this.schema).ifNotExists().execute()
150
+ }
151
+ const { error, results } = await this.migrator.migrateToLatest()
152
+ if (error) {
153
+ throw error
154
+ }
155
+ if (!results) {
156
+ throw new Error('An unknown failure occurred while migrating')
157
+ }
158
+ return results
159
+ }
160
+ }
161
+
162
+ export default Database
163
+
164
+ const onPoolError = (err: Error) => dbLogger.error({ err }, 'db pool error')
165
+ const onClientError = (err: Error) => dbLogger.error({ err }, 'db client error')
166
+
167
+ // utils
168
+ // -------
169
+
170
+ class LeakyTxPlugin implements KyselyPlugin {
171
+ private txOver: boolean
172
+
173
+ endTx() {
174
+ this.txOver = true
175
+ }
176
+
177
+ transformQuery(args: PluginTransformQueryArgs): RootOperationNode {
178
+ if (this.txOver) {
179
+ throw new Error('tx already failed')
180
+ }
181
+ return args.node
182
+ }
183
+
184
+ async transformResult(
185
+ args: PluginTransformResultArgs,
186
+ ): Promise<QueryResult<UnknownRow>> {
187
+ return args.result
188
+ }
189
+ }
190
+
191
+ type TxnEmitter = TypedEmitter<TxnEvents>
192
+
193
+ type TxnEvents = {
194
+ commit: () => void
195
+ }
196
+
197
+ const noopAsync = async () => {}
@@ -0,0 +1,164 @@
1
+ import { Kysely } from 'kysely'
2
+
3
+ export async function up(db: Kysely<unknown>): Promise<void> {
4
+ // Moderation event
5
+ await db.schema
6
+ .createTable('moderation_event')
7
+ .addColumn('id', 'serial', (col) => col.primaryKey())
8
+ .addColumn('action', 'varchar', (col) => col.notNull())
9
+ .addColumn('subjectType', 'varchar', (col) => col.notNull())
10
+ .addColumn('subjectDid', 'varchar', (col) => col.notNull())
11
+ .addColumn('subjectUri', 'varchar')
12
+ .addColumn('subjectCid', 'varchar')
13
+ .addColumn('comment', 'text')
14
+ .addColumn('meta', 'jsonb')
15
+ .addColumn('createdAt', 'varchar', (col) => col.notNull())
16
+ .addColumn('createdBy', 'varchar', (col) => col.notNull())
17
+ .addColumn('reversedAt', 'varchar')
18
+ .addColumn('reversedBy', 'varchar')
19
+ .addColumn('durationInHours', 'integer')
20
+ .addColumn('expiresAt', 'varchar')
21
+ .addColumn('reversedReason', 'text')
22
+ .addColumn('createLabelVals', 'varchar')
23
+ .addColumn('negateLabelVals', 'varchar')
24
+ .addColumn('legacyRefId', 'integer')
25
+ .execute()
26
+
27
+ // Moderation subject status
28
+ await db.schema
29
+ .createTable('moderation_subject_status')
30
+ .addColumn('id', 'serial', (col) => col.primaryKey())
31
+
32
+ // Identifiers
33
+ .addColumn('did', 'varchar', (col) => col.notNull())
34
+ // Default to '' so that we can apply unique constraints on did and recordPath columns
35
+ .addColumn('recordPath', 'varchar', (col) => col.notNull().defaultTo(''))
36
+ .addColumn('blobCids', 'jsonb')
37
+ .addColumn('recordCid', 'varchar')
38
+
39
+ // human review team state
40
+ .addColumn('reviewState', 'varchar', (col) => col.notNull())
41
+ .addColumn('comment', 'varchar')
42
+ .addColumn('muteUntil', 'varchar')
43
+ .addColumn('lastReviewedAt', 'varchar')
44
+ .addColumn('lastReviewedBy', 'varchar')
45
+
46
+ // report state
47
+ .addColumn('lastReportedAt', 'varchar')
48
+ .addColumn('lastAppealedAt', 'varchar')
49
+
50
+ // visibility/intervention state
51
+ .addColumn('takendown', 'boolean', (col) => col.defaultTo(false).notNull())
52
+ .addColumn('suspendUntil', 'varchar')
53
+ .addColumn('appealed', 'boolean')
54
+
55
+ // timestamps
56
+ .addColumn('createdAt', 'varchar', (col) => col.notNull())
57
+ .addColumn('updatedAt', 'varchar', (col) => col.notNull())
58
+ .addUniqueConstraint('moderation_status_unique_idx', ['did', 'recordPath'])
59
+ .execute()
60
+
61
+ await db.schema
62
+ .createIndex('moderation_subject_status_blob_cids_idx')
63
+ .on('moderation_subject_status')
64
+ .using('gin')
65
+ .column('blobCids')
66
+ .execute()
67
+
68
+ // Label
69
+ await db.schema
70
+ .createTable('label')
71
+ .addColumn('src', 'varchar', (col) => col.notNull())
72
+ .addColumn('uri', 'varchar', (col) => col.notNull())
73
+ .addColumn('cid', 'varchar', (col) => col.notNull())
74
+ .addColumn('val', 'varchar', (col) => col.notNull())
75
+ .addColumn('neg', 'boolean', (col) => col.notNull())
76
+ .addColumn('cts', 'varchar', (col) => col.notNull())
77
+ .addPrimaryKeyConstraint('label_pkey', ['src', 'uri', 'cid', 'val'])
78
+ .execute()
79
+ await db.schema
80
+ .createIndex('label_uri_index')
81
+ .on('label')
82
+ .column('uri')
83
+ .execute()
84
+
85
+ // Push Events
86
+ await db.schema
87
+ .createTable('repo_push_event')
88
+ .addColumn('id', 'serial', (col) => col.primaryKey())
89
+ .addColumn('eventType', 'varchar', (col) => col.notNull())
90
+ .addColumn('subjectDid', 'varchar', (col) => col.notNull())
91
+ .addColumn('takedownRef', 'varchar')
92
+ .addColumn('confirmedAt', 'timestamptz')
93
+ .addColumn('lastAttempted', 'timestamptz')
94
+ .addColumn('attempts', 'integer', (col) => col.notNull().defaultTo(0))
95
+ .addUniqueConstraint('repo_push_event_unique_evt', [
96
+ 'subjectDid',
97
+ 'eventType',
98
+ ])
99
+ .execute()
100
+ await db.schema
101
+ .createIndex('repo_push_confirmation_idx')
102
+ .on('repo_push_event')
103
+ .columns(['confirmedAt', 'attempts'])
104
+ .execute()
105
+
106
+ await db.schema
107
+ .createTable('record_push_event')
108
+ .addColumn('id', 'serial', (col) => col.primaryKey())
109
+ .addColumn('eventType', 'varchar', (col) => col.notNull())
110
+ .addColumn('subjectDid', 'varchar', (col) => col.notNull())
111
+ .addColumn('subjectUri', 'varchar', (col) => col.notNull())
112
+ .addColumn('subjectCid', 'varchar')
113
+ .addColumn('takedownRef', 'varchar')
114
+ .addColumn('confirmedAt', 'timestamptz')
115
+ .addColumn('lastAttempted', 'timestamptz')
116
+ .addColumn('attempts', 'integer', (col) => col.notNull().defaultTo(0))
117
+ .addUniqueConstraint('record_push_event_unique_evt', [
118
+ 'subjectUri',
119
+ 'eventType',
120
+ ])
121
+ .execute()
122
+ await db.schema
123
+ .createIndex('record_push_event_did_type_idx')
124
+ .on('record_push_event')
125
+ .columns(['subjectDid', 'eventType'])
126
+ .execute()
127
+ await db.schema
128
+ .createIndex('record_push_confirmation_idx')
129
+ .on('record_push_event')
130
+ .columns(['confirmedAt', 'attempts'])
131
+ .execute()
132
+
133
+ await db.schema
134
+ .createTable('blob_push_event')
135
+ .addColumn('id', 'serial', (col) => col.primaryKey())
136
+ .addColumn('eventType', 'varchar', (col) => col.notNull())
137
+ .addColumn('subjectDid', 'varchar', (col) => col.notNull())
138
+ .addColumn('subjectBlobCid', 'varchar', (col) => col.notNull())
139
+ .addColumn('subjectUri', 'varchar')
140
+ .addColumn('takedownRef', 'varchar')
141
+ .addColumn('confirmedAt', 'timestamptz')
142
+ .addColumn('lastAttempted', 'timestamptz')
143
+ .addColumn('attempts', 'integer', (col) => col.notNull().defaultTo(0))
144
+ .addUniqueConstraint('blob_push_event_unique_evt', [
145
+ 'subjectDid',
146
+ 'subjectBlobCid',
147
+ 'eventType',
148
+ ])
149
+ .execute()
150
+ await db.schema
151
+ .createIndex('blob_push_confirmation_idx')
152
+ .on('blob_push_event')
153
+ .columns(['confirmedAt', 'attempts'])
154
+ .execute()
155
+ }
156
+
157
+ export async function down(db: Kysely<unknown>): Promise<void> {
158
+ await db.schema.dropTable('moderation_event').execute()
159
+ await db.schema.dropTable('moderation_subject_status').execute()
160
+ await db.schema.dropTable('label').execute()
161
+ await db.schema.dropTable('repo_push_event').execute()
162
+ await db.schema.dropTable('record_push_event').execute()
163
+ await db.schema.dropTable('blob_push_event').execute()
164
+ }
@@ -0,0 +1,5 @@
1
+ // NOTE this file can be edited by hand, but it is also appended to by the migration:create command.
2
+ // It's important that every migration is exported from here with the proper name. We'd simplify
3
+ // this with kysely's FileMigrationProvider, but it doesn't play nicely with the build process.
4
+
5
+ export * as _20231219T205730722Z from './20231219T205730722Z-init'
@@ -0,0 +1,25 @@
1
+ import { Kysely, Migration, MigrationProvider } from 'kysely'
2
+
3
+ // Passes a context argument to migrations. We use this to thread the dialect into migrations
4
+
5
+ export class CtxMigrationProvider<T> implements MigrationProvider {
6
+ constructor(
7
+ private migrations: Record<string, CtxMigration<T>>,
8
+ private ctx: T,
9
+ ) {}
10
+ async getMigrations(): Promise<Record<string, Migration>> {
11
+ const ctxMigrations: Record<string, Migration> = {}
12
+ Object.entries(this.migrations).forEach(([name, migration]) => {
13
+ ctxMigrations[name] = {
14
+ up: async (db) => await migration.up(db, this.ctx),
15
+ down: async (db) => await migration.down?.(db, this.ctx),
16
+ }
17
+ })
18
+ return ctxMigrations
19
+ }
20
+ }
21
+
22
+ export interface CtxMigration<T> {
23
+ up(db: Kysely<unknown>, ctx: T): Promise<void>
24
+ down?(db: Kysely<unknown>, ctx: T): Promise<void>
25
+ }
@@ -0,0 +1,216 @@
1
+ import { sql, DynamicModule } from 'kysely'
2
+ import { InvalidRequestError } from '@atproto/xrpc-server'
3
+ import { AnyQb, DbRef } from './types'
4
+
5
+ export type Cursor = { primary: string; secondary: string }
6
+ export type LabeledResult = {
7
+ primary: string | number
8
+ secondary: string | number
9
+ }
10
+
11
+ /**
12
+ * The GenericKeyset is an abstract class that sets-up the interface and partial implementation
13
+ * of a keyset-paginated cursor with two parts. There are three types involved:
14
+ * - Result: a raw result (i.e. a row from the db) containing data that will make-up a cursor.
15
+ * - E.g. { createdAt: '2022-01-01T12:00:00Z', cid: 'bafyx' }
16
+ * - LabeledResult: a Result processed such that the "primary" and "secondary" parts of the cursor are labeled.
17
+ * - E.g. { primary: '2022-01-01T12:00:00Z', secondary: 'bafyx' }
18
+ * - Cursor: the two string parts that make-up the packed/string cursor.
19
+ * - E.g. packed cursor '1641038400000::bafyx' in parts { primary: '1641038400000', secondary: 'bafyx' }
20
+ *
21
+ * These types relate as such. Implementers define the relations marked with a *:
22
+ * Result -*-> LabeledResult <-*-> Cursor <--> packed/string cursor
23
+ * ↳ SQL Condition
24
+ */
25
+ export abstract class GenericKeyset<R, LR extends LabeledResult> {
26
+ constructor(public primary: DbRef, public secondary: DbRef) {}
27
+ abstract labelResult(result: R): LR
28
+ abstract labeledResultToCursor(labeled: LR): Cursor
29
+ abstract cursorToLabeledResult(cursor: Cursor): LR
30
+ packFromResult(results: R | R[]): string | undefined {
31
+ const result = Array.isArray(results) ? results.at(-1) : results
32
+ if (!result) return
33
+ return this.pack(this.labelResult(result))
34
+ }
35
+ pack(labeled?: LR): string | undefined {
36
+ if (!labeled) return
37
+ const cursor = this.labeledResultToCursor(labeled)
38
+ return this.packCursor(cursor)
39
+ }
40
+ unpack(cursorStr?: string): LR | undefined {
41
+ const cursor = this.unpackCursor(cursorStr)
42
+ if (!cursor) return
43
+ return this.cursorToLabeledResult(cursor)
44
+ }
45
+ packCursor(cursor?: Cursor): string | undefined {
46
+ if (!cursor) return
47
+ return `${cursor.primary}::${cursor.secondary}`
48
+ }
49
+ unpackCursor(cursorStr?: string): Cursor | undefined {
50
+ if (!cursorStr) return
51
+ const result = cursorStr.split('::')
52
+ const [primary, secondary, ...others] = result
53
+ if (!primary || !secondary || others.length > 0) {
54
+ throw new InvalidRequestError('Malformed cursor')
55
+ }
56
+ return {
57
+ primary,
58
+ secondary,
59
+ }
60
+ }
61
+ getSql(labeled?: LR, direction?: 'asc' | 'desc', tryIndex?: boolean) {
62
+ if (labeled === undefined) return
63
+ if (tryIndex) {
64
+ // The tryIndex param will likely disappear and become the default implementation: here for now for gradual rollout query-by-query.
65
+ if (direction === 'asc') {
66
+ return sql`((${this.primary}, ${this.secondary}) > (${labeled.primary}, ${labeled.secondary}))`
67
+ } else {
68
+ return sql`((${this.primary}, ${this.secondary}) < (${labeled.primary}, ${labeled.secondary}))`
69
+ }
70
+ } else {
71
+ // @NOTE this implementation can struggle to use an index on (primary, secondary) for pagination due to the "or" usage.
72
+ if (direction === 'asc') {
73
+ return sql`((${this.primary} > ${labeled.primary}) or (${this.primary} = ${labeled.primary} and ${this.secondary} > ${labeled.secondary}))`
74
+ } else {
75
+ return sql`((${this.primary} < ${labeled.primary}) or (${this.primary} = ${labeled.primary} and ${this.secondary} < ${labeled.secondary}))`
76
+ }
77
+ }
78
+ }
79
+ }
80
+
81
+ type StatusKeysetParam = {
82
+ lastReviewedAt: string | null
83
+ lastReportedAt: string | null
84
+ id: number
85
+ }
86
+
87
+ export class StatusKeyset extends GenericKeyset<StatusKeysetParam, Cursor> {
88
+ labelResult(result: StatusKeysetParam): Cursor
89
+ labelResult(result: StatusKeysetParam) {
90
+ const primaryField = (
91
+ this.primary as ReturnType<DynamicModule['ref']>
92
+ ).dynamicReference.includes('lastReviewedAt')
93
+ ? 'lastReviewedAt'
94
+ : 'lastReportedAt'
95
+
96
+ return {
97
+ primary: result[primaryField]
98
+ ? new Date(`${result[primaryField]}`).getTime().toString()
99
+ : '',
100
+ secondary: result.id.toString(),
101
+ }
102
+ }
103
+ labeledResultToCursor(labeled: Cursor) {
104
+ return {
105
+ primary: labeled.primary,
106
+ secondary: labeled.secondary,
107
+ }
108
+ }
109
+ cursorToLabeledResult(cursor: Cursor) {
110
+ return {
111
+ primary: cursor.primary
112
+ ? new Date(parseInt(cursor.primary, 10)).toISOString()
113
+ : '',
114
+ secondary: cursor.secondary,
115
+ }
116
+ }
117
+ unpackCursor(cursorStr?: string): Cursor | undefined {
118
+ if (!cursorStr) return
119
+ const result = cursorStr.split('::')
120
+ const [primary, secondary, ...others] = result
121
+ if (!secondary || others.length > 0) {
122
+ throw new InvalidRequestError('Malformed cursor')
123
+ }
124
+ return {
125
+ primary,
126
+ secondary,
127
+ }
128
+ }
129
+ // This is specifically built to handle nullable columns as primary sorting column
130
+ getSql(labeled?: Cursor, direction?: 'asc' | 'desc') {
131
+ if (labeled === undefined) return
132
+ if (direction === 'asc') {
133
+ return !labeled.primary
134
+ ? sql`(${this.primary} IS NULL AND ${this.secondary} > ${labeled.secondary})`
135
+ : sql`((${this.primary}, ${this.secondary}) > (${labeled.primary}, ${labeled.secondary}) OR (${this.primary} is null))`
136
+ } else {
137
+ return !labeled.primary
138
+ ? sql`(${this.primary} IS NULL AND ${this.secondary} < ${labeled.secondary})`
139
+ : sql`((${this.primary}, ${this.secondary}) < (${labeled.primary}, ${labeled.secondary}) OR (${this.primary} is null))`
140
+ }
141
+ }
142
+ }
143
+
144
+ type TimeIdKeysetParam = {
145
+ id: number
146
+ createdAt: string
147
+ }
148
+ type TimeIdResult = TimeIdKeysetParam
149
+
150
+ export class TimeIdKeyset extends GenericKeyset<TimeIdKeysetParam, Cursor> {
151
+ labelResult(result: TimeIdResult): Cursor
152
+ labelResult(result: TimeIdResult) {
153
+ return { primary: result.createdAt, secondary: result.id.toString() }
154
+ }
155
+ labeledResultToCursor(labeled: Cursor) {
156
+ return {
157
+ primary: new Date(labeled.primary).getTime().toString(),
158
+ secondary: labeled.secondary,
159
+ }
160
+ }
161
+ cursorToLabeledResult(cursor: Cursor) {
162
+ const primaryDate = new Date(parseInt(cursor.primary, 10))
163
+ if (isNaN(primaryDate.getTime())) {
164
+ throw new InvalidRequestError('Malformed cursor')
165
+ }
166
+ return {
167
+ primary: primaryDate.toISOString(),
168
+ secondary: cursor.secondary,
169
+ }
170
+ }
171
+ }
172
+
173
+ export const paginate = <
174
+ QB extends AnyQb,
175
+ K extends GenericKeyset<unknown, any>,
176
+ >(
177
+ qb: QB,
178
+ opts: {
179
+ limit?: number
180
+ cursor?: string
181
+ direction?: 'asc' | 'desc'
182
+ keyset: K
183
+ tryIndex?: boolean
184
+ // By default, pg does nullsFirst
185
+ nullsLast?: boolean
186
+ },
187
+ ): QB => {
188
+ const {
189
+ limit,
190
+ cursor,
191
+ keyset,
192
+ direction = 'desc',
193
+ tryIndex,
194
+ nullsLast,
195
+ } = opts
196
+ const keysetSql = keyset.getSql(keyset.unpack(cursor), direction, tryIndex)
197
+ return qb
198
+ .if(!!limit, (q) => q.limit(limit as number))
199
+ .if(!nullsLast, (q) =>
200
+ q.orderBy(keyset.primary, direction).orderBy(keyset.secondary, direction),
201
+ )
202
+ .if(!!nullsLast, (q) =>
203
+ q
204
+ .orderBy(
205
+ direction === 'asc'
206
+ ? sql`${keyset.primary} asc nulls last`
207
+ : sql`${keyset.primary} desc nulls last`,
208
+ )
209
+ .orderBy(
210
+ direction === 'asc'
211
+ ? sql`${keyset.secondary} asc nulls last`
212
+ : sql`${keyset.secondary} desc nulls last`,
213
+ ),
214
+ )
215
+ .if(!!keysetSql, (qb) => (keysetSql ? qb.where(keysetSql) : qb)) as QB
216
+ }
@@ -0,0 +1,21 @@
1
+ import { Generated } from 'kysely'
2
+
3
+ export const eventTableName = 'blob_push_event'
4
+
5
+ export type BlobPushEventType = 'pds_takedown' | 'appview_takedown'
6
+
7
+ export interface BlobPushEvent {
8
+ id: Generated<number>
9
+ eventType: BlobPushEventType
10
+ subjectDid: string
11
+ subjectBlobCid: string
12
+ subjectUri: string | null
13
+ takedownRef: string | null
14
+ confirmedAt: Date | null
15
+ lastAttempted: Date | null
16
+ attempts: Generated<number>
17
+ }
18
+
19
+ export type PartialDB = {
20
+ [eventTableName]: BlobPushEvent
21
+ }
@@ -0,0 +1,18 @@
1
+ import { Kysely } from 'kysely'
2
+ import * as modEvent from './moderation_event'
3
+ import * as modSubjectStatus from './moderation_subject_status'
4
+ import * as repoPushEvent from './repo_push_event'
5
+ import * as recordPushEvent from './record_push_event'
6
+ import * as blobPushEvent from './blob_push_event'
7
+ import * as label from './label'
8
+
9
+ export type DatabaseSchemaType = modEvent.PartialDB &
10
+ modSubjectStatus.PartialDB &
11
+ label.PartialDB &
12
+ repoPushEvent.PartialDB &
13
+ recordPushEvent.PartialDB &
14
+ blobPushEvent.PartialDB
15
+
16
+ export type DatabaseSchema = Kysely<DatabaseSchemaType>
17
+
18
+ export default DatabaseSchema
@@ -0,0 +1,12 @@
1
+ export const tableName = 'label'
2
+
3
+ export interface Label {
4
+ src: string
5
+ uri: string
6
+ cid: string
7
+ val: string
8
+ neg: boolean
9
+ cts: string
10
+ }
11
+
12
+ export type PartialDB = { [tableName]: Label }