@atproto/bsky 0.0.15 → 0.0.17

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 (236) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/api/com/atproto/moderation/util.d.ts +4 -3
  3. package/dist/cache/read-through.d.ts +30 -0
  4. package/dist/config.d.ts +18 -0
  5. package/dist/context.d.ts +21 -6
  6. package/dist/daemon/config.d.ts +15 -0
  7. package/dist/daemon/context.d.ts +15 -0
  8. package/dist/daemon/index.d.ts +23 -0
  9. package/dist/daemon/logger.d.ts +3 -0
  10. package/dist/daemon/notifications.d.ts +18 -0
  11. package/dist/daemon/services.d.ts +11 -0
  12. package/dist/db/database-schema.d.ts +1 -2
  13. package/dist/db/index.js +41 -1
  14. package/dist/db/index.js.map +3 -3
  15. package/dist/db/migrations/20231003T202833377Z-create-moderation-subject-status.d.ts +3 -0
  16. package/dist/db/migrations/20231205T000257238Z-remove-did-cache.d.ts +3 -0
  17. package/dist/db/migrations/index.d.ts +2 -0
  18. package/dist/db/pagination.d.ts +2 -1
  19. package/dist/db/{periodic-moderation-action-reversal.d.ts → periodic-moderation-event-reversal.d.ts} +3 -5
  20. package/dist/db/tables/moderation.d.ts +24 -34
  21. package/dist/did-cache.d.ts +10 -7
  22. package/dist/feed-gen/types.d.ts +1 -1
  23. package/dist/index.d.ts +6 -1
  24. package/dist/index.js +4370 -2758
  25. package/dist/index.js.map +3 -3
  26. package/dist/indexer/context.d.ts +2 -0
  27. package/dist/indexer/index.d.ts +1 -0
  28. package/dist/lexicon/index.d.ts +23 -18
  29. package/dist/lexicon/lexicons.d.ts +561 -412
  30. package/dist/lexicon/types/app/bsky/feed/defs.d.ts +1 -7
  31. package/dist/lexicon/types/app/bsky/graph/defs.d.ts +1 -0
  32. package/dist/lexicon/types/com/atproto/admin/defs.d.ts +114 -48
  33. package/dist/lexicon/types/com/atproto/admin/{resolveModerationReports.d.ts → deleteAccount.d.ts} +2 -13
  34. package/dist/lexicon/types/com/atproto/admin/{takeModerationAction.d.ts → emitModerationEvent.d.ts} +5 -6
  35. package/dist/lexicon/types/com/atproto/admin/{getModerationAction.d.ts → getModerationEvent.d.ts} +1 -1
  36. package/dist/lexicon/types/com/atproto/admin/{getModerationActions.d.ts → queryModerationEvents.d.ts} +5 -1
  37. package/dist/lexicon/types/com/atproto/admin/{getModerationReports.d.ts → queryModerationStatuses.d.ts} +12 -6
  38. package/dist/lexicon/types/com/atproto/admin/sendEmail.d.ts +1 -0
  39. package/dist/lexicon/types/com/atproto/{admin/getModerationReport.d.ts → temp/importRepo.d.ts} +10 -7
  40. package/dist/lexicon/types/com/atproto/temp/pushBlob.d.ts +25 -0
  41. package/dist/lexicon/types/com/atproto/{admin/reverseModerationAction.d.ts → temp/transferAccount.d.ts} +11 -5
  42. package/dist/logger.d.ts +1 -0
  43. package/dist/migrate-moderation-data.d.ts +1 -0
  44. package/dist/redis.d.ts +10 -1
  45. package/dist/services/actor/index.d.ts +18 -4
  46. package/dist/services/actor/views.d.ts +6 -8
  47. package/dist/services/feed/index.d.ts +7 -4
  48. package/dist/services/feed/util.d.ts +9 -1
  49. package/dist/services/feed/views.d.ts +11 -21
  50. package/dist/services/graph/index.d.ts +5 -29
  51. package/dist/services/graph/types.d.ts +1 -0
  52. package/dist/services/index.d.ts +3 -7
  53. package/dist/services/label/index.d.ts +10 -4
  54. package/dist/services/moderation/index.d.ts +134 -72
  55. package/dist/services/moderation/pagination.d.ts +36 -0
  56. package/dist/services/moderation/status.d.ts +13 -0
  57. package/dist/services/moderation/types.d.ts +35 -0
  58. package/dist/services/moderation/views.d.ts +18 -14
  59. package/dist/services/types.d.ts +3 -0
  60. package/dist/services/util/notification.d.ts +5 -0
  61. package/dist/services/util/post.d.ts +6 -6
  62. package/dist/util/debug.d.ts +1 -1
  63. package/dist/util/retry.d.ts +1 -6
  64. package/package.json +11 -11
  65. package/src/api/app/bsky/feed/getActorFeeds.ts +2 -1
  66. package/src/api/app/bsky/feed/getActorLikes.ts +1 -3
  67. package/src/api/app/bsky/feed/getAuthorFeed.ts +1 -3
  68. package/src/api/app/bsky/feed/getFeed.ts +9 -9
  69. package/src/api/app/bsky/feed/getFeedGenerator.ts +3 -0
  70. package/src/api/app/bsky/feed/getFeedGenerators.ts +2 -1
  71. package/src/api/app/bsky/feed/getListFeed.ts +1 -3
  72. package/src/api/app/bsky/feed/getPostThread.ts +15 -54
  73. package/src/api/app/bsky/feed/getPosts.ts +21 -18
  74. package/src/api/app/bsky/feed/getSuggestedFeeds.ts +2 -1
  75. package/src/api/app/bsky/feed/getTimeline.ts +1 -3
  76. package/src/api/app/bsky/feed/searchPosts.ts +20 -17
  77. package/src/api/app/bsky/graph/getList.ts +6 -3
  78. package/src/api/app/bsky/graph/getListBlocks.ts +3 -2
  79. package/src/api/app/bsky/graph/getListMutes.ts +2 -1
  80. package/src/api/app/bsky/graph/getLists.ts +2 -1
  81. package/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +3 -1
  82. package/src/api/blob-resolver.ts +6 -11
  83. package/src/api/com/atproto/admin/emitModerationEvent.ts +220 -0
  84. package/src/api/com/atproto/admin/{getModerationActions.ts → getModerationEvent.ts} +5 -11
  85. package/src/api/com/atproto/admin/getRecord.ts +1 -0
  86. package/src/api/com/atproto/admin/{getModerationReports.ts → queryModerationEvents.ts} +13 -16
  87. package/src/api/com/atproto/admin/queryModerationStatuses.ts +55 -0
  88. package/src/api/com/atproto/moderation/createReport.ts +9 -7
  89. package/src/api/com/atproto/moderation/util.ts +38 -20
  90. package/src/api/index.ts +8 -14
  91. package/src/auth.ts +29 -21
  92. package/src/auto-moderator/index.ts +26 -19
  93. package/src/cache/read-through.ts +151 -0
  94. package/src/config.ts +90 -1
  95. package/src/context.ts +11 -7
  96. package/src/daemon/config.ts +60 -0
  97. package/src/daemon/context.ts +27 -0
  98. package/src/daemon/index.ts +78 -0
  99. package/src/daemon/logger.ts +6 -0
  100. package/src/daemon/notifications.ts +54 -0
  101. package/src/daemon/services.ts +22 -0
  102. package/src/db/database-schema.ts +0 -2
  103. package/src/db/migrations/20231003T202833377Z-create-moderation-subject-status.ts +123 -0
  104. package/src/db/migrations/20231205T000257238Z-remove-did-cache.ts +14 -0
  105. package/src/db/migrations/index.ts +2 -0
  106. package/src/db/pagination.ts +26 -3
  107. package/src/db/{periodic-moderation-action-reversal.ts → periodic-moderation-event-reversal.ts} +50 -46
  108. package/src/db/tables/moderation.ts +35 -52
  109. package/src/did-cache.ts +33 -56
  110. package/src/feed-gen/bsky-team.ts +1 -1
  111. package/src/feed-gen/hot-classic.ts +1 -1
  112. package/src/feed-gen/index.ts +0 -4
  113. package/src/feed-gen/mutuals.ts +6 -2
  114. package/src/feed-gen/types.ts +1 -1
  115. package/src/index.ts +57 -17
  116. package/src/indexer/context.ts +5 -0
  117. package/src/indexer/index.ts +10 -7
  118. package/src/lexicon/index.ts +80 -67
  119. package/src/lexicon/lexicons.ts +698 -507
  120. package/src/lexicon/types/app/bsky/feed/defs.ts +1 -18
  121. package/src/lexicon/types/app/bsky/graph/defs.ts +1 -0
  122. package/src/lexicon/types/com/atproto/admin/defs.ts +276 -84
  123. package/src/lexicon/types/com/atproto/admin/{resolveModerationReports.ts → deleteAccount.ts} +2 -13
  124. package/src/lexicon/types/com/atproto/admin/{takeModerationAction.ts → emitModerationEvent.ts} +13 -11
  125. package/src/lexicon/types/com/atproto/admin/{getModerationReport.ts → getModerationEvent.ts} +1 -1
  126. package/src/lexicon/types/com/atproto/admin/{getModerationActions.ts → queryModerationEvents.ts} +8 -1
  127. package/src/lexicon/types/com/atproto/admin/{getModerationReports.ts → queryModerationStatuses.ts} +21 -14
  128. package/src/lexicon/types/com/atproto/admin/sendEmail.ts +1 -0
  129. package/src/lexicon/types/com/atproto/{admin/getModerationAction.ts → temp/importRepo.ts} +11 -7
  130. package/src/lexicon/types/com/atproto/temp/pushBlob.ts +39 -0
  131. package/src/lexicon/types/com/atproto/{admin/reverseModerationAction.ts → temp/transferAccount.ts} +18 -5
  132. package/src/logger.ts +2 -0
  133. package/src/migrate-moderation-data.ts +414 -0
  134. package/src/redis.ts +43 -3
  135. package/src/services/actor/index.ts +55 -7
  136. package/src/services/actor/views.ts +18 -21
  137. package/src/services/feed/index.ts +52 -19
  138. package/src/services/feed/util.ts +47 -19
  139. package/src/services/feed/views.ts +87 -13
  140. package/src/services/graph/index.ts +21 -3
  141. package/src/services/graph/types.ts +1 -0
  142. package/src/services/index.ts +14 -14
  143. package/src/services/indexing/index.ts +7 -10
  144. package/src/services/indexing/plugins/block.ts +2 -3
  145. package/src/services/indexing/plugins/feed-generator.ts +2 -3
  146. package/src/services/indexing/plugins/follow.ts +2 -3
  147. package/src/services/indexing/plugins/like.ts +2 -3
  148. package/src/services/indexing/plugins/list-block.ts +2 -3
  149. package/src/services/indexing/plugins/list-item.ts +2 -3
  150. package/src/services/indexing/plugins/list.ts +2 -3
  151. package/src/services/indexing/plugins/post.ts +16 -4
  152. package/src/services/indexing/plugins/repost.ts +2 -3
  153. package/src/services/indexing/plugins/thread-gate.ts +2 -3
  154. package/src/services/label/index.ts +68 -25
  155. package/src/services/moderation/index.ts +380 -395
  156. package/src/services/moderation/pagination.ts +96 -0
  157. package/src/services/moderation/status.ts +241 -0
  158. package/src/services/moderation/types.ts +49 -0
  159. package/src/services/moderation/views.ts +278 -329
  160. package/src/services/types.ts +4 -0
  161. package/src/services/util/notification.ts +70 -0
  162. package/src/util/debug.ts +2 -2
  163. package/src/util/retry.ts +1 -44
  164. package/tests/__snapshots__/feed-generation.test.ts.snap +322 -6
  165. package/tests/__snapshots__/indexing.test.ts.snap +0 -6
  166. package/tests/admin/__snapshots__/get-record.test.ts.snap +30 -132
  167. package/tests/admin/__snapshots__/get-repo.test.ts.snap +14 -60
  168. package/tests/admin/__snapshots__/moderation-events.test.ts.snap +146 -0
  169. package/tests/admin/__snapshots__/moderation-statuses.test.ts.snap +64 -0
  170. package/tests/admin/__snapshots__/moderation.test.ts.snap +0 -125
  171. package/tests/admin/get-record.test.ts +5 -9
  172. package/tests/admin/get-repo.test.ts +10 -12
  173. package/tests/admin/moderation-events.test.ts +221 -0
  174. package/tests/admin/moderation-statuses.test.ts +145 -0
  175. package/tests/admin/moderation.test.ts +512 -860
  176. package/tests/admin/repo-search.test.ts +3 -3
  177. package/tests/algos/hot-classic.test.ts +1 -2
  178. package/tests/auth.test.ts +1 -1
  179. package/tests/auto-moderator/fuzzy-matcher.test.ts +2 -1
  180. package/tests/auto-moderator/labeler.test.ts +19 -20
  181. package/tests/auto-moderator/takedowns.test.ts +61 -28
  182. package/tests/blob-resolver.test.ts +4 -2
  183. package/tests/daemon.test.ts +191 -0
  184. package/tests/did-cache.test.ts +20 -5
  185. package/tests/feed-generation.test.ts +57 -9
  186. package/tests/handle-invalidation.test.ts +1 -5
  187. package/tests/indexing.test.ts +20 -13
  188. package/tests/redis-cache.test.ts +231 -0
  189. package/tests/seeds/basic.ts +3 -0
  190. package/tests/subscription/repo.test.ts +4 -7
  191. package/tests/views/__snapshots__/block-lists.test.ts.snap +3 -9
  192. package/tests/views/__snapshots__/blocks.test.ts.snap +0 -9
  193. package/tests/views/__snapshots__/mute-lists.test.ts.snap +5 -5
  194. package/tests/views/__snapshots__/mutes.test.ts.snap +0 -3
  195. package/tests/views/__snapshots__/thread.test.ts.snap +0 -30
  196. package/tests/views/actor-search.test.ts +2 -3
  197. package/tests/views/author-feed.test.ts +42 -36
  198. package/tests/views/follows.test.ts +40 -35
  199. package/tests/views/list-feed.test.ts +17 -9
  200. package/tests/views/notifications.test.ts +13 -9
  201. package/tests/views/profile.test.ts +20 -19
  202. package/tests/views/thread.test.ts +117 -94
  203. package/tests/views/threadgating.test.ts +89 -19
  204. package/tests/views/timeline.test.ts +21 -13
  205. package/dist/api/com/atproto/admin/resolveModerationReports.d.ts +0 -3
  206. package/dist/api/com/atproto/admin/reverseModerationAction.d.ts +0 -3
  207. package/dist/api/com/atproto/admin/takeModerationAction.d.ts +0 -3
  208. package/dist/db/tables/did-cache.d.ts +0 -10
  209. package/dist/feed-gen/best-of-follows.d.ts +0 -29
  210. package/dist/feed-gen/whats-hot.d.ts +0 -29
  211. package/dist/feed-gen/with-friends.d.ts +0 -3
  212. package/dist/label-cache.d.ts +0 -19
  213. package/src/api/com/atproto/admin/getModerationAction.ts +0 -44
  214. package/src/api/com/atproto/admin/getModerationReport.ts +0 -43
  215. package/src/api/com/atproto/admin/resolveModerationReports.ts +0 -24
  216. package/src/api/com/atproto/admin/reverseModerationAction.ts +0 -115
  217. package/src/api/com/atproto/admin/takeModerationAction.ts +0 -156
  218. package/src/db/tables/did-cache.ts +0 -13
  219. package/src/feed-gen/best-of-follows.ts +0 -74
  220. package/src/feed-gen/whats-hot.ts +0 -101
  221. package/src/feed-gen/with-friends.ts +0 -39
  222. package/src/label-cache.ts +0 -90
  223. package/tests/admin/__snapshots__/get-moderation-action.test.ts.snap +0 -172
  224. package/tests/admin/__snapshots__/get-moderation-actions.test.ts.snap +0 -178
  225. package/tests/admin/__snapshots__/get-moderation-report.test.ts.snap +0 -177
  226. package/tests/admin/__snapshots__/get-moderation-reports.test.ts.snap +0 -307
  227. package/tests/admin/get-moderation-action.test.ts +0 -100
  228. package/tests/admin/get-moderation-actions.test.ts +0 -164
  229. package/tests/admin/get-moderation-report.test.ts +0 -100
  230. package/tests/admin/get-moderation-reports.test.ts +0 -332
  231. package/tests/algos/whats-hot.test.ts +0 -118
  232. package/tests/algos/with-friends.test.ts +0 -145
  233. /package/dist/api/com/atproto/admin/{getModerationAction.d.ts → emitModerationEvent.d.ts} +0 -0
  234. /package/dist/api/com/atproto/admin/{getModerationActions.d.ts → getModerationEvent.d.ts} +0 -0
  235. /package/dist/api/com/atproto/admin/{getModerationReport.d.ts → queryModerationEvents.d.ts} +0 -0
  236. /package/dist/api/com/atproto/admin/{getModerationReports.d.ts → queryModerationStatuses.d.ts} +0 -0
@@ -2,28 +2,28 @@ import DatabaseSchema from '../../db/database-schema';
2
2
  export declare const getDescendentsQb: (db: DatabaseSchema, opts: {
3
3
  uri: string;
4
4
  depth: number;
5
- }) => import("kysely/dist/cjs/parser/with-parser").QueryCreatorWithCommonTableExpression<import("../../db/database-schema").DatabaseSchemaType, "descendent(uri, depth)", (cte: import("kysely").QueryCreator<import("../../db/tables/duplicate-record").PartialDB & import("../../db/tables/profile").PartialDB & import("../../db/tables/profile-agg").PartialDB & import("../../db/tables/post").PartialDB & import("../../db/tables/post-embed").PartialDB & import("../../db/tables/post-agg").PartialDB & import("../../db/tables/repost").PartialDB & import("../../db/tables/thread-gate").PartialDB & import("../../db/tables/feed-item").PartialDB & import("../../db/tables/follow").PartialDB & import("../../db/tables/like").PartialDB & import("../../db/tables/list").PartialDB & import("../../db/tables/list-item").PartialDB & import("../../db/tables/list-mute").PartialDB & import("../../db/tables/list-block").PartialDB & import("../../db/tables/mute").PartialDB & import("../../db/tables/actor-block").PartialDB & import("../../db/tables/feed-generator").PartialDB & import("../../db/tables/subscription").PartialDB & import("../../db/tables/actor").PartialDB & import("../../db/tables/actor-state").PartialDB & import("../../db/tables/actor-sync").PartialDB & import("../../db/tables/record").PartialDB & import("../../db/tables/notification").PartialDB & import("../../db/tables/notification-push-token").PartialDB & import("../../db/tables/did-cache").PartialDB & import("../../db/tables/moderation").PartialDB & import("../../db/tables/label").PartialDB & import("../../db/tables/algo").PartialDB & import("../../db/tables/view-param").PartialDB & import("../../db/tables/suggested-follow").PartialDB & import("../../db/tables/suggested-feed").PartialDB & Record<"descendent", {
5
+ }) => import("kysely/dist/cjs/parser/with-parser").QueryCreatorWithCommonTableExpression<import("../../db/database-schema").DatabaseSchemaType, "descendent(uri, depth)", (cte: import("kysely").QueryCreator<import("../../db/tables/duplicate-record").PartialDB & import("../../db/tables/profile").PartialDB & import("../../db/tables/profile-agg").PartialDB & import("../../db/tables/post").PartialDB & import("../../db/tables/post-embed").PartialDB & import("../../db/tables/post-agg").PartialDB & import("../../db/tables/repost").PartialDB & import("../../db/tables/thread-gate").PartialDB & import("../../db/tables/feed-item").PartialDB & import("../../db/tables/follow").PartialDB & import("../../db/tables/like").PartialDB & import("../../db/tables/list").PartialDB & import("../../db/tables/list-item").PartialDB & import("../../db/tables/list-mute").PartialDB & import("../../db/tables/list-block").PartialDB & import("../../db/tables/mute").PartialDB & import("../../db/tables/actor-block").PartialDB & import("../../db/tables/feed-generator").PartialDB & import("../../db/tables/subscription").PartialDB & import("../../db/tables/actor").PartialDB & import("../../db/tables/actor-state").PartialDB & import("../../db/tables/actor-sync").PartialDB & import("../../db/tables/record").PartialDB & import("../../db/tables/notification").PartialDB & import("../../db/tables/notification-push-token").PartialDB & import("../../db/tables/moderation").PartialDB & import("../../db/tables/label").PartialDB & import("../../db/tables/algo").PartialDB & import("../../db/tables/view-param").PartialDB & import("../../db/tables/suggested-follow").PartialDB & import("../../db/tables/suggested-feed").PartialDB & Record<"descendent", {
6
6
  uri: any;
7
7
  depth: any;
8
- }>>) => import("kysely").SelectQueryBuilder<import("kysely/dist/cjs/parser/table-parser").From<import("../../db/tables/duplicate-record").PartialDB & import("../../db/tables/profile").PartialDB & import("../../db/tables/profile-agg").PartialDB & import("../../db/tables/post").PartialDB & import("../../db/tables/post-embed").PartialDB & import("../../db/tables/post-agg").PartialDB & import("../../db/tables/repost").PartialDB & import("../../db/tables/thread-gate").PartialDB & import("../../db/tables/feed-item").PartialDB & import("../../db/tables/follow").PartialDB & import("../../db/tables/like").PartialDB & import("../../db/tables/list").PartialDB & import("../../db/tables/list-item").PartialDB & import("../../db/tables/list-mute").PartialDB & import("../../db/tables/list-block").PartialDB & import("../../db/tables/mute").PartialDB & import("../../db/tables/actor-block").PartialDB & import("../../db/tables/feed-generator").PartialDB & import("../../db/tables/subscription").PartialDB & import("../../db/tables/actor").PartialDB & import("../../db/tables/actor-state").PartialDB & import("../../db/tables/actor-sync").PartialDB & import("../../db/tables/record").PartialDB & import("../../db/tables/notification").PartialDB & import("../../db/tables/notification-push-token").PartialDB & import("../../db/tables/did-cache").PartialDB & import("../../db/tables/moderation").PartialDB & import("../../db/tables/label").PartialDB & import("../../db/tables/algo").PartialDB & import("../../db/tables/view-param").PartialDB & import("../../db/tables/suggested-follow").PartialDB & import("../../db/tables/suggested-feed").PartialDB & Record<"descendent", {
8
+ }>>) => import("kysely").SelectQueryBuilder<import("kysely/dist/cjs/parser/table-parser").From<import("../../db/tables/duplicate-record").PartialDB & import("../../db/tables/profile").PartialDB & import("../../db/tables/profile-agg").PartialDB & import("../../db/tables/post").PartialDB & import("../../db/tables/post-embed").PartialDB & import("../../db/tables/post-agg").PartialDB & import("../../db/tables/repost").PartialDB & import("../../db/tables/thread-gate").PartialDB & import("../../db/tables/feed-item").PartialDB & import("../../db/tables/follow").PartialDB & import("../../db/tables/like").PartialDB & import("../../db/tables/list").PartialDB & import("../../db/tables/list-item").PartialDB & import("../../db/tables/list-mute").PartialDB & import("../../db/tables/list-block").PartialDB & import("../../db/tables/mute").PartialDB & import("../../db/tables/actor-block").PartialDB & import("../../db/tables/feed-generator").PartialDB & import("../../db/tables/subscription").PartialDB & import("../../db/tables/actor").PartialDB & import("../../db/tables/actor-state").PartialDB & import("../../db/tables/actor-sync").PartialDB & import("../../db/tables/record").PartialDB & import("../../db/tables/notification").PartialDB & import("../../db/tables/notification-push-token").PartialDB & import("../../db/tables/moderation").PartialDB & import("../../db/tables/label").PartialDB & import("../../db/tables/algo").PartialDB & import("../../db/tables/view-param").PartialDB & import("../../db/tables/suggested-follow").PartialDB & import("../../db/tables/suggested-feed").PartialDB & Record<"descendent", {
9
9
  uri: any;
10
10
  depth: any;
11
- }>, "post">, "post", import("kysely").Selection<import("kysely/dist/cjs/parser/table-parser").From<import("../../db/tables/duplicate-record").PartialDB & import("../../db/tables/profile").PartialDB & import("../../db/tables/profile-agg").PartialDB & import("../../db/tables/post").PartialDB & import("../../db/tables/post-embed").PartialDB & import("../../db/tables/post-agg").PartialDB & import("../../db/tables/repost").PartialDB & import("../../db/tables/thread-gate").PartialDB & import("../../db/tables/feed-item").PartialDB & import("../../db/tables/follow").PartialDB & import("../../db/tables/like").PartialDB & import("../../db/tables/list").PartialDB & import("../../db/tables/list-item").PartialDB & import("../../db/tables/list-mute").PartialDB & import("../../db/tables/list-block").PartialDB & import("../../db/tables/mute").PartialDB & import("../../db/tables/actor-block").PartialDB & import("../../db/tables/feed-generator").PartialDB & import("../../db/tables/subscription").PartialDB & import("../../db/tables/actor").PartialDB & import("../../db/tables/actor-state").PartialDB & import("../../db/tables/actor-sync").PartialDB & import("../../db/tables/record").PartialDB & import("../../db/tables/notification").PartialDB & import("../../db/tables/notification-push-token").PartialDB & import("../../db/tables/did-cache").PartialDB & import("../../db/tables/moderation").PartialDB & import("../../db/tables/label").PartialDB & import("../../db/tables/algo").PartialDB & import("../../db/tables/view-param").PartialDB & import("../../db/tables/suggested-follow").PartialDB & import("../../db/tables/suggested-feed").PartialDB & Record<"descendent", {
11
+ }>, "post">, "post", import("kysely").Selection<import("kysely/dist/cjs/parser/table-parser").From<import("../../db/tables/duplicate-record").PartialDB & import("../../db/tables/profile").PartialDB & import("../../db/tables/profile-agg").PartialDB & import("../../db/tables/post").PartialDB & import("../../db/tables/post-embed").PartialDB & import("../../db/tables/post-agg").PartialDB & import("../../db/tables/repost").PartialDB & import("../../db/tables/thread-gate").PartialDB & import("../../db/tables/feed-item").PartialDB & import("../../db/tables/follow").PartialDB & import("../../db/tables/like").PartialDB & import("../../db/tables/list").PartialDB & import("../../db/tables/list-item").PartialDB & import("../../db/tables/list-mute").PartialDB & import("../../db/tables/list-block").PartialDB & import("../../db/tables/mute").PartialDB & import("../../db/tables/actor-block").PartialDB & import("../../db/tables/feed-generator").PartialDB & import("../../db/tables/subscription").PartialDB & import("../../db/tables/actor").PartialDB & import("../../db/tables/actor-state").PartialDB & import("../../db/tables/actor-sync").PartialDB & import("../../db/tables/record").PartialDB & import("../../db/tables/notification").PartialDB & import("../../db/tables/notification-push-token").PartialDB & import("../../db/tables/moderation").PartialDB & import("../../db/tables/label").PartialDB & import("../../db/tables/algo").PartialDB & import("../../db/tables/view-param").PartialDB & import("../../db/tables/suggested-follow").PartialDB & import("../../db/tables/suggested-feed").PartialDB & Record<"descendent", {
12
12
  uri: any;
13
13
  depth: any;
14
14
  }>, "post">, "post", "post.uri as uri" | import("kysely").AliasedRawBuilder<number, "depth">>>>;
15
15
  export declare const getAncestorsAndSelfQb: (db: DatabaseSchema, opts: {
16
16
  uri: string;
17
17
  parentHeight: number;
18
- }) => import("kysely/dist/cjs/parser/with-parser").QueryCreatorWithCommonTableExpression<import("../../db/database-schema").DatabaseSchemaType, "ancestor(uri, ancestorUri, height)", (cte: import("kysely").QueryCreator<import("../../db/tables/duplicate-record").PartialDB & import("../../db/tables/profile").PartialDB & import("../../db/tables/profile-agg").PartialDB & import("../../db/tables/post").PartialDB & import("../../db/tables/post-embed").PartialDB & import("../../db/tables/post-agg").PartialDB & import("../../db/tables/repost").PartialDB & import("../../db/tables/thread-gate").PartialDB & import("../../db/tables/feed-item").PartialDB & import("../../db/tables/follow").PartialDB & import("../../db/tables/like").PartialDB & import("../../db/tables/list").PartialDB & import("../../db/tables/list-item").PartialDB & import("../../db/tables/list-mute").PartialDB & import("../../db/tables/list-block").PartialDB & import("../../db/tables/mute").PartialDB & import("../../db/tables/actor-block").PartialDB & import("../../db/tables/feed-generator").PartialDB & import("../../db/tables/subscription").PartialDB & import("../../db/tables/actor").PartialDB & import("../../db/tables/actor-state").PartialDB & import("../../db/tables/actor-sync").PartialDB & import("../../db/tables/record").PartialDB & import("../../db/tables/notification").PartialDB & import("../../db/tables/notification-push-token").PartialDB & import("../../db/tables/did-cache").PartialDB & import("../../db/tables/moderation").PartialDB & import("../../db/tables/label").PartialDB & import("../../db/tables/algo").PartialDB & import("../../db/tables/view-param").PartialDB & import("../../db/tables/suggested-follow").PartialDB & import("../../db/tables/suggested-feed").PartialDB & Record<"ancestor", {
18
+ }) => import("kysely/dist/cjs/parser/with-parser").QueryCreatorWithCommonTableExpression<import("../../db/database-schema").DatabaseSchemaType, "ancestor(uri, ancestorUri, height)", (cte: import("kysely").QueryCreator<import("../../db/tables/duplicate-record").PartialDB & import("../../db/tables/profile").PartialDB & import("../../db/tables/profile-agg").PartialDB & import("../../db/tables/post").PartialDB & import("../../db/tables/post-embed").PartialDB & import("../../db/tables/post-agg").PartialDB & import("../../db/tables/repost").PartialDB & import("../../db/tables/thread-gate").PartialDB & import("../../db/tables/feed-item").PartialDB & import("../../db/tables/follow").PartialDB & import("../../db/tables/like").PartialDB & import("../../db/tables/list").PartialDB & import("../../db/tables/list-item").PartialDB & import("../../db/tables/list-mute").PartialDB & import("../../db/tables/list-block").PartialDB & import("../../db/tables/mute").PartialDB & import("../../db/tables/actor-block").PartialDB & import("../../db/tables/feed-generator").PartialDB & import("../../db/tables/subscription").PartialDB & import("../../db/tables/actor").PartialDB & import("../../db/tables/actor-state").PartialDB & import("../../db/tables/actor-sync").PartialDB & import("../../db/tables/record").PartialDB & import("../../db/tables/notification").PartialDB & import("../../db/tables/notification-push-token").PartialDB & import("../../db/tables/moderation").PartialDB & import("../../db/tables/label").PartialDB & import("../../db/tables/algo").PartialDB & import("../../db/tables/view-param").PartialDB & import("../../db/tables/suggested-follow").PartialDB & import("../../db/tables/suggested-feed").PartialDB & Record<"ancestor", {
19
19
  uri: any;
20
20
  height: any;
21
21
  ancestorUri: any;
22
- }>>) => import("kysely").SelectQueryBuilder<import("kysely/dist/cjs/parser/table-parser").From<import("../../db/tables/duplicate-record").PartialDB & import("../../db/tables/profile").PartialDB & import("../../db/tables/profile-agg").PartialDB & import("../../db/tables/post").PartialDB & import("../../db/tables/post-embed").PartialDB & import("../../db/tables/post-agg").PartialDB & import("../../db/tables/repost").PartialDB & import("../../db/tables/thread-gate").PartialDB & import("../../db/tables/feed-item").PartialDB & import("../../db/tables/follow").PartialDB & import("../../db/tables/like").PartialDB & import("../../db/tables/list").PartialDB & import("../../db/tables/list-item").PartialDB & import("../../db/tables/list-mute").PartialDB & import("../../db/tables/list-block").PartialDB & import("../../db/tables/mute").PartialDB & import("../../db/tables/actor-block").PartialDB & import("../../db/tables/feed-generator").PartialDB & import("../../db/tables/subscription").PartialDB & import("../../db/tables/actor").PartialDB & import("../../db/tables/actor-state").PartialDB & import("../../db/tables/actor-sync").PartialDB & import("../../db/tables/record").PartialDB & import("../../db/tables/notification").PartialDB & import("../../db/tables/notification-push-token").PartialDB & import("../../db/tables/did-cache").PartialDB & import("../../db/tables/moderation").PartialDB & import("../../db/tables/label").PartialDB & import("../../db/tables/algo").PartialDB & import("../../db/tables/view-param").PartialDB & import("../../db/tables/suggested-follow").PartialDB & import("../../db/tables/suggested-feed").PartialDB & Record<"ancestor", {
22
+ }>>) => import("kysely").SelectQueryBuilder<import("kysely/dist/cjs/parser/table-parser").From<import("../../db/tables/duplicate-record").PartialDB & import("../../db/tables/profile").PartialDB & import("../../db/tables/profile-agg").PartialDB & import("../../db/tables/post").PartialDB & import("../../db/tables/post-embed").PartialDB & import("../../db/tables/post-agg").PartialDB & import("../../db/tables/repost").PartialDB & import("../../db/tables/thread-gate").PartialDB & import("../../db/tables/feed-item").PartialDB & import("../../db/tables/follow").PartialDB & import("../../db/tables/like").PartialDB & import("../../db/tables/list").PartialDB & import("../../db/tables/list-item").PartialDB & import("../../db/tables/list-mute").PartialDB & import("../../db/tables/list-block").PartialDB & import("../../db/tables/mute").PartialDB & import("../../db/tables/actor-block").PartialDB & import("../../db/tables/feed-generator").PartialDB & import("../../db/tables/subscription").PartialDB & import("../../db/tables/actor").PartialDB & import("../../db/tables/actor-state").PartialDB & import("../../db/tables/actor-sync").PartialDB & import("../../db/tables/record").PartialDB & import("../../db/tables/notification").PartialDB & import("../../db/tables/notification-push-token").PartialDB & import("../../db/tables/moderation").PartialDB & import("../../db/tables/label").PartialDB & import("../../db/tables/algo").PartialDB & import("../../db/tables/view-param").PartialDB & import("../../db/tables/suggested-follow").PartialDB & import("../../db/tables/suggested-feed").PartialDB & Record<"ancestor", {
23
23
  uri: any;
24
24
  height: any;
25
25
  ancestorUri: any;
26
- }>, "post">, "post", import("kysely").Selection<import("kysely/dist/cjs/parser/table-parser").From<import("../../db/tables/duplicate-record").PartialDB & import("../../db/tables/profile").PartialDB & import("../../db/tables/profile-agg").PartialDB & import("../../db/tables/post").PartialDB & import("../../db/tables/post-embed").PartialDB & import("../../db/tables/post-agg").PartialDB & import("../../db/tables/repost").PartialDB & import("../../db/tables/thread-gate").PartialDB & import("../../db/tables/feed-item").PartialDB & import("../../db/tables/follow").PartialDB & import("../../db/tables/like").PartialDB & import("../../db/tables/list").PartialDB & import("../../db/tables/list-item").PartialDB & import("../../db/tables/list-mute").PartialDB & import("../../db/tables/list-block").PartialDB & import("../../db/tables/mute").PartialDB & import("../../db/tables/actor-block").PartialDB & import("../../db/tables/feed-generator").PartialDB & import("../../db/tables/subscription").PartialDB & import("../../db/tables/actor").PartialDB & import("../../db/tables/actor-state").PartialDB & import("../../db/tables/actor-sync").PartialDB & import("../../db/tables/record").PartialDB & import("../../db/tables/notification").PartialDB & import("../../db/tables/notification-push-token").PartialDB & import("../../db/tables/did-cache").PartialDB & import("../../db/tables/moderation").PartialDB & import("../../db/tables/label").PartialDB & import("../../db/tables/algo").PartialDB & import("../../db/tables/view-param").PartialDB & import("../../db/tables/suggested-follow").PartialDB & import("../../db/tables/suggested-feed").PartialDB & Record<"ancestor", {
26
+ }>, "post">, "post", import("kysely").Selection<import("kysely/dist/cjs/parser/table-parser").From<import("../../db/tables/duplicate-record").PartialDB & import("../../db/tables/profile").PartialDB & import("../../db/tables/profile-agg").PartialDB & import("../../db/tables/post").PartialDB & import("../../db/tables/post-embed").PartialDB & import("../../db/tables/post-agg").PartialDB & import("../../db/tables/repost").PartialDB & import("../../db/tables/thread-gate").PartialDB & import("../../db/tables/feed-item").PartialDB & import("../../db/tables/follow").PartialDB & import("../../db/tables/like").PartialDB & import("../../db/tables/list").PartialDB & import("../../db/tables/list-item").PartialDB & import("../../db/tables/list-mute").PartialDB & import("../../db/tables/list-block").PartialDB & import("../../db/tables/mute").PartialDB & import("../../db/tables/actor-block").PartialDB & import("../../db/tables/feed-generator").PartialDB & import("../../db/tables/subscription").PartialDB & import("../../db/tables/actor").PartialDB & import("../../db/tables/actor-state").PartialDB & import("../../db/tables/actor-sync").PartialDB & import("../../db/tables/record").PartialDB & import("../../db/tables/notification").PartialDB & import("../../db/tables/notification-push-token").PartialDB & import("../../db/tables/moderation").PartialDB & import("../../db/tables/label").PartialDB & import("../../db/tables/algo").PartialDB & import("../../db/tables/view-param").PartialDB & import("../../db/tables/suggested-follow").PartialDB & import("../../db/tables/suggested-feed").PartialDB & Record<"ancestor", {
27
27
  uri: any;
28
28
  height: any;
29
29
  ancestorUri: any;
@@ -1 +1 @@
1
- export declare const debugCatch: <Func extends (...args: any[]) => any>(fn: Func) => (...args: any[]) => Promise<any>;
1
+ export declare const debugCatch: <Func extends (...args: any[]) => any>(fn: Func) => (...args: Parameters<Func>) => Promise<ReturnType<Func>>;
@@ -1,8 +1,3 @@
1
- export declare function retry<T>(fn: () => Promise<T>, opts?: RetryOptions): Promise<T>;
1
+ import { RetryOptions } from '@atproto/common';
2
2
  export declare function retryHttp<T>(fn: () => Promise<T>, opts?: RetryOptions): Promise<T>;
3
3
  export declare function retryableHttp(err: unknown): boolean;
4
- declare type RetryOptions = {
5
- max?: number;
6
- retryable?: (err: unknown) => boolean;
7
- };
8
- export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/bsky",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "license": "MIT",
5
5
  "description": "Reference implementation of app.bsky App View (Bluesky API)",
6
6
  "keywords": [
@@ -35,14 +35,14 @@
35
35
  "sharp": "^0.32.6",
36
36
  "typed-emitter": "^2.1.0",
37
37
  "uint8arrays": "3.0.0",
38
- "@atproto/api": "^0.6.23",
38
+ "@atproto/api": "^0.7.0",
39
39
  "@atproto/common": "^0.3.3",
40
40
  "@atproto/crypto": "^0.3.0",
41
- "@atproto/syntax": "^0.1.4",
41
+ "@atproto/syntax": "^0.1.5",
42
42
  "@atproto/identity": "^0.3.2",
43
- "@atproto/lexicon": "^0.3.0",
44
- "@atproto/repo": "^0.3.5",
45
- "@atproto/xrpc-server": "^0.4.1"
43
+ "@atproto/lexicon": "^0.3.1",
44
+ "@atproto/repo": "^0.3.6",
45
+ "@atproto/xrpc-server": "^0.4.2"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@did-plc/server": "^0.0.1",
@@ -52,11 +52,11 @@
52
52
  "@types/pg": "^8.6.6",
53
53
  "@types/qs": "^6.9.7",
54
54
  "axios": "^0.27.2",
55
- "@atproto/api": "^0.6.23",
56
- "@atproto/dev-env": "^0.2.15",
57
- "@atproto/lex-cli": "^0.2.4",
58
- "@atproto/pds": "^0.3.3",
59
- "@atproto/xrpc": "^0.4.0"
55
+ "@atproto/api": "^0.7.0",
56
+ "@atproto/dev-env": "^0.2.17",
57
+ "@atproto/lex-cli": "^0.2.5",
58
+ "@atproto/pds": "^0.3.5",
59
+ "@atproto/xrpc": "^0.4.1"
60
60
  },
61
61
  "scripts": {
62
62
  "codegen": "lex gen-server ./src/lexicon ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/*",
@@ -1,4 +1,5 @@
1
1
  import { InvalidRequestError } from '@atproto/xrpc-server'
2
+ import { mapDefined } from '@atproto/common'
2
3
  import { Server } from '../../../../lexicon'
3
4
  import AppContext from '../../../../context'
4
5
  import { TimeCidKeyset, paginate } from '../../../../db/pagination'
@@ -42,7 +43,7 @@ export default function (server: Server, ctx: AppContext) {
42
43
  throw new InvalidRequestError(`Actor not found: ${actor}`)
43
44
  }
44
45
 
45
- const feeds = feedsRes.map((row) => {
46
+ const feeds = mapDefined(feedsRes, (row) => {
46
47
  const feed = {
47
48
  ...row,
48
49
  viewer: viewer ? { like: row.viewerLike } : undefined,
@@ -107,9 +107,7 @@ const noPostBlocks = (state: HydrationState) => {
107
107
  const presentation = (state: HydrationState, ctx: Context) => {
108
108
  const { feedService } = ctx
109
109
  const { feedItems, cursor, params } = state
110
- const feed = feedService.views.formatFeed(feedItems, state, {
111
- viewer: params.viewer,
112
- })
110
+ const feed = feedService.views.formatFeed(feedItems, state, params.viewer)
113
111
  return { feed, cursor }
114
112
  }
115
113
 
@@ -147,9 +147,7 @@ const noBlocksOrMutedReposts = (state: HydrationState) => {
147
147
  const presentation = (state: HydrationState, ctx: Context) => {
148
148
  const { feedService } = ctx
149
149
  const { feedItems, cursor, params } = state
150
- const feed = feedService.views.formatFeed(feedItems, state, {
151
- viewer: params.viewer,
152
- })
150
+ const feed = feedService.views.formatFeed(feedItems, state, params.viewer)
153
151
  return { feed, cursor }
154
152
  }
155
153
 
@@ -33,7 +33,7 @@ export default function (server: Server, ctx: AppContext) {
33
33
  presentation,
34
34
  )
35
35
  server.app.bsky.feed.getFeed({
36
- auth: ctx.authVerifierAnyAudience,
36
+ auth: ctx.authOptionalVerifierAnyAudience,
37
37
  handler: async ({ params, auth, req }) => {
38
38
  const db = ctx.db.getReplica()
39
39
  const feedService = ctx.services.feed(db)
@@ -98,22 +98,22 @@ const hydration = async (state: SkeletonState, ctx: Context) => {
98
98
 
99
99
  const noBlocksOrMutes = (state: HydrationState) => {
100
100
  const { viewer } = state.params
101
- state.feedItems = state.feedItems.filter(
102
- (item) =>
101
+ state.feedItems = state.feedItems.filter((item) => {
102
+ if (!viewer) return true
103
+ return (
103
104
  !state.bam.block([viewer, item.postAuthorDid]) &&
104
105
  !state.bam.block([viewer, item.originatorDid]) &&
105
106
  !state.bam.mute([viewer, item.postAuthorDid]) &&
106
- !state.bam.mute([viewer, item.originatorDid]),
107
- )
107
+ !state.bam.mute([viewer, item.originatorDid])
108
+ )
109
+ })
108
110
  return state
109
111
  }
110
112
 
111
113
  const presentation = (state: HydrationState, ctx: Context) => {
112
114
  const { feedService } = ctx
113
115
  const { feedItems, cursor, passthrough, params } = state
114
- const feed = feedService.views.formatFeed(feedItems, state, {
115
- viewer: params.viewer,
116
- })
116
+ const feed = feedService.views.formatFeed(feedItems, state, params.viewer)
117
117
  return {
118
118
  feed,
119
119
  cursor,
@@ -130,7 +130,7 @@ type Context = {
130
130
  authorization?: string
131
131
  }
132
132
 
133
- type Params = GetFeedParams & { viewer: string }
133
+ type Params = GetFeedParams & { viewer: string | null }
134
134
 
135
135
  type SkeletonState = {
136
136
  params: Params
@@ -55,6 +55,9 @@ export default function (server: Server, ctx: AppContext) {
55
55
  feedInfo,
56
56
  profiles,
57
57
  )
58
+ if (!feedView) {
59
+ throw new InvalidRequestError('could not find feed')
60
+ }
58
61
 
59
62
  return {
60
63
  encoding: 'application/json',
@@ -1,3 +1,4 @@
1
+ import { mapDefined } from '@atproto/common'
1
2
  import { Server } from '../../../../lexicon'
2
3
  import AppContext from '../../../../context'
3
4
  import { FeedGenInfo, FeedService } from '../../../../services/feed'
@@ -60,7 +61,7 @@ const hydration = async (state: SkeletonState, ctx: Context) => {
60
61
 
61
62
  const presentation = (state: HydrationState, ctx: Context) => {
62
63
  const { feedService } = ctx
63
- const feeds = state.generators.map((gen) =>
64
+ const feeds = mapDefined(state.generators, (gen) =>
64
65
  feedService.views.formatFeedGeneratorView(gen, state.profiles),
65
66
  )
66
67
  return { feeds }
@@ -105,9 +105,7 @@ const noBlocksOrMutes = (state: HydrationState) => {
105
105
  const presentation = (state: HydrationState, ctx: Context) => {
106
106
  const { feedService } = ctx
107
107
  const { feedItems, cursor, params } = state
108
- const feed = feedService.views.formatFeed(feedItems, state, {
109
- viewer: params.viewer,
110
- })
108
+ const feed = feedService.views.formatFeed(feedItems, state, params.viewer)
111
109
  return { feed, cursor }
112
110
  }
113
111
 
@@ -6,27 +6,21 @@ import {
6
6
  NotFoundPost,
7
7
  ThreadViewPost,
8
8
  isNotFoundPost,
9
- isThreadViewPost,
10
9
  } from '../../../../lexicon/types/app/bsky/feed/defs'
11
- import { Record as PostRecord } from '../../../../lexicon/types/app/bsky/feed/post'
12
- import { Record as ThreadgateRecord } from '../../../../lexicon/types/app/bsky/feed/threadgate'
13
10
  import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getPostThread'
14
11
  import AppContext from '../../../../context'
15
12
  import {
16
13
  FeedService,
17
14
  FeedRow,
18
15
  FeedHydrationState,
19
- PostInfo,
20
16
  } from '../../../../services/feed'
21
17
  import {
22
18
  getAncestorsAndSelfQb,
23
19
  getDescendentsQb,
24
20
  } from '../../../../services/util/post'
25
21
  import { Database } from '../../../../db'
26
- import DatabaseSchema from '../../../../db/database-schema'
27
22
  import { setRepoRev } from '../../../util'
28
23
  import { ActorInfoMap, ActorService } from '../../../../services/actor'
29
- import { violatesThreadGate } from '../../../../services/feed/util'
30
24
  import { createPipeline, noRules } from '../../../../pipeline'
31
25
 
32
26
  export default function (server: Server, ctx: AppContext) {
@@ -80,21 +74,7 @@ const hydration = async (state: SkeletonState, ctx: Context) => {
80
74
  } = state
81
75
  const relevant = getRelevantIds(threadData)
82
76
  const hydrated = await feedService.feedHydration({ ...relevant, viewer })
83
- // check root reply interaction rules
84
- const anchorPostUri = threadData.post.postUri
85
- const rootUri = threadData.post.replyRoot || anchorPostUri
86
- const anchor = hydrated.posts[anchorPostUri]
87
- const root = hydrated.posts[rootUri]
88
- const gate = hydrated.threadgates[rootUri]?.record
89
- const viewerCanReply = await checkViewerCanReply(
90
- ctx.db.db,
91
- anchor ?? null,
92
- viewer,
93
- new AtUri(rootUri).host,
94
- (root?.record ?? null) as PostRecord | null,
95
- gate ?? null,
96
- )
97
- return { ...state, ...hydrated, viewerCanReply }
77
+ return { ...state, ...hydrated }
98
78
  }
99
79
 
100
80
  const presentation = (state: HydrationState, ctx: Context) => {
@@ -103,16 +83,19 @@ const presentation = (state: HydrationState, ctx: Context) => {
103
83
  const actors = actorService.views.profileBasicPresentation(
104
84
  Object.keys(profiles),
105
85
  state,
106
- { viewer: params.viewer },
86
+ params.viewer,
87
+ )
88
+ const thread = composeThread(
89
+ state.threadData,
90
+ actors,
91
+ state,
92
+ ctx,
93
+ params.viewer,
107
94
  )
108
- const thread = composeThread(state.threadData, actors, state, ctx)
109
95
  if (isNotFoundPost(thread)) {
110
96
  // @TODO technically this could be returned as a NotFoundPost based on lexicon
111
97
  throw new InvalidRequestError(`Post not found: ${params.uri}`, 'NotFound')
112
98
  }
113
- if (isThreadViewPost(thread) && params.viewer) {
114
- thread.viewer = { canReply: state.viewerCanReply }
115
- }
116
99
  return { thread }
117
100
  }
118
101
 
@@ -121,6 +104,7 @@ const composeThread = (
121
104
  actors: ActorInfoMap,
122
105
  state: HydrationState,
123
106
  ctx: Context,
107
+ viewer: string | null,
124
108
  ) => {
125
109
  const { feedService } = ctx
126
110
  const { posts, threadgates, embeds, blocks, labels, lists } = state
@@ -133,6 +117,7 @@ const composeThread = (
133
117
  embeds,
134
118
  labels,
135
119
  lists,
120
+ viewer,
136
121
  )
137
122
 
138
123
  // replies that are invalid due to reply-gating:
@@ -179,14 +164,14 @@ const composeThread = (
179
164
  notFound: true,
180
165
  }
181
166
  } else {
182
- parent = composeThread(threadData.parent, actors, state, ctx)
167
+ parent = composeThread(threadData.parent, actors, state, ctx, viewer)
183
168
  }
184
169
  }
185
170
 
186
171
  let replies: (ThreadViewPost | NotFoundPost | BlockedPost)[] | undefined
187
172
  if (threadData.replies && !badReply) {
188
173
  replies = threadData.replies.flatMap((reply) => {
189
- const thread = composeThread(reply, actors, state, ctx)
174
+ const thread = composeThread(reply, actors, state, ctx, viewer)
190
175
  // e.g. don't bother including #postNotFound reply placeholders for takedowns. either way matches api contract.
191
176
  const skip = []
192
177
  return isNotFoundPost(thread) ? skip : thread
@@ -223,6 +208,7 @@ const getRelevantIds = (
223
208
  if (thread.post.replyRoot) {
224
209
  // ensure root is included for checking interactions
225
210
  uris.add(thread.post.replyRoot)
211
+ dids.add(new AtUri(thread.post.replyRoot).hostname)
226
212
  }
227
213
  return { dids, uris }
228
214
  }
@@ -317,28 +303,6 @@ const getChildrenData = (
317
303
  }))
318
304
  }
319
305
 
320
- const checkViewerCanReply = async (
321
- db: DatabaseSchema,
322
- anchor: PostInfo | null,
323
- viewer: string | null,
324
- owner: string,
325
- root: PostRecord | null,
326
- threadgate: ThreadgateRecord | null,
327
- ) => {
328
- if (!viewer) return false
329
- // @TODO re-enable invalidReplyRoot check
330
- // if (anchor?.invalidReplyRoot || anchor?.violatesThreadGate) return false
331
- if (anchor?.violatesThreadGate) return false
332
- const viewerViolatesThreadGate = await violatesThreadGate(
333
- db,
334
- viewer,
335
- owner,
336
- root,
337
- threadgate,
338
- )
339
- return !viewerViolatesThreadGate
340
- }
341
-
342
306
  class ParentNotFoundError extends Error {
343
307
  constructor(public uri: string) {
344
308
  super(`Parent not found: ${uri}`)
@@ -364,7 +328,4 @@ type SkeletonState = {
364
328
  threadData: PostThread
365
329
  }
366
330
 
367
- type HydrationState = SkeletonState &
368
- FeedHydrationState & {
369
- viewerCanReply: boolean
370
- }
331
+ type HydrationState = SkeletonState & FeedHydrationState
@@ -1,10 +1,13 @@
1
1
  import { dedupeStrs } from '@atproto/common'
2
- import { AtUri } from '@atproto/syntax'
3
2
  import { Server } from '../../../../lexicon'
4
3
  import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getPosts'
5
4
  import AppContext from '../../../../context'
6
5
  import { Database } from '../../../../db'
7
- import { FeedHydrationState, FeedService } from '../../../../services/feed'
6
+ import {
7
+ FeedHydrationState,
8
+ FeedRow,
9
+ FeedService,
10
+ } from '../../../../services/feed'
8
11
  import { createPipeline } from '../../../../pipeline'
9
12
  import { ActorService } from '../../../../services/actor'
10
13
 
@@ -31,18 +34,18 @@ export default function (server: Server, ctx: AppContext) {
31
34
  })
32
35
  }
33
36
 
34
- const skeleton = async (params: Params) => {
35
- return { params, postUris: dedupeStrs(params.uris) }
37
+ const skeleton = async (params: Params, ctx: Context) => {
38
+ const deduped = dedupeStrs(params.uris)
39
+ const feedItems = await ctx.feedService.postUrisToFeedItems(deduped)
40
+ return { params, feedItems }
36
41
  }
37
42
 
38
43
  const hydration = async (state: SkeletonState, ctx: Context) => {
39
44
  const { feedService } = ctx
40
- const { params, postUris } = state
41
- const uris = new Set<string>(postUris)
42
- const dids = new Set<string>(postUris.map((uri) => new AtUri(uri).hostname))
45
+ const { params, feedItems } = state
46
+ const refs = feedService.feedItemRefs(feedItems)
43
47
  const hydrated = await feedService.feedHydration({
44
- uris,
45
- dids,
48
+ ...refs,
46
49
  viewer: params.viewer,
47
50
  })
48
51
  return { ...state, ...hydrated }
@@ -50,32 +53,32 @@ const hydration = async (state: SkeletonState, ctx: Context) => {
50
53
 
51
54
  const noBlocks = (state: HydrationState) => {
52
55
  const { viewer } = state.params
53
- state.postUris = state.postUris.filter((uri) => {
54
- const post = state.posts[uri]
55
- if (!viewer || !post) return true
56
- return !state.bam.block([viewer, post.creator])
56
+ state.feedItems = state.feedItems.filter((item) => {
57
+ if (!viewer) return true
58
+ return !state.bam.block([viewer, item.postAuthorDid])
57
59
  })
58
60
  return state
59
61
  }
60
62
 
61
63
  const presentation = (state: HydrationState, ctx: Context) => {
62
64
  const { feedService, actorService } = ctx
63
- const { postUris, profiles, params } = state
65
+ const { feedItems, profiles, params } = state
64
66
  const SKIP = []
65
67
  const actors = actorService.views.profileBasicPresentation(
66
68
  Object.keys(profiles),
67
69
  state,
68
- { viewer: params.viewer },
70
+ params.viewer,
69
71
  )
70
- const postViews = postUris.flatMap((uri) => {
72
+ const postViews = feedItems.flatMap((item) => {
71
73
  const postView = feedService.views.formatPostView(
72
- uri,
74
+ item.postUri,
73
75
  actors,
74
76
  state.posts,
75
77
  state.threadgates,
76
78
  state.embeds,
77
79
  state.labels,
78
80
  state.lists,
81
+ params.viewer,
79
82
  )
80
83
  return postView ?? SKIP
81
84
  })
@@ -92,7 +95,7 @@ type Params = QueryParams & { viewer: string | null }
92
95
 
93
96
  type SkeletonState = {
94
97
  params: Params
95
- postUris: string[]
98
+ feedItems: FeedRow[]
96
99
  }
97
100
 
98
101
  type HydrationState = SkeletonState & FeedHydrationState
@@ -1,3 +1,4 @@
1
+ import { mapDefined } from '@atproto/common'
1
2
  import { Server } from '../../../../lexicon'
2
3
  import AppContext from '../../../../context'
3
4
 
@@ -23,7 +24,7 @@ export default function (server: Server, ctx: AppContext) {
23
24
  const creators = genList.map((gen) => gen.creator)
24
25
  const profiles = await actorService.views.profilesBasic(creators, viewer)
25
26
 
26
- const feedViews = genList.map((gen) =>
27
+ const feedViews = mapDefined(genList, (gen) =>
27
28
  feedService.views.formatFeedGeneratorView(gen, profiles),
28
29
  )
29
30
 
@@ -146,9 +146,7 @@ const noBlocksOrMutes = (state: HydrationState): HydrationState => {
146
146
  const presentation = (state: HydrationState, ctx: Context) => {
147
147
  const { feedService } = ctx
148
148
  const { feedItems, cursor, params } = state
149
- const feed = feedService.views.formatFeed(feedItems, state, {
150
- viewer: params.viewer,
151
- })
149
+ const feed = feedService.views.formatFeed(feedItems, state, params.viewer)
152
150
  return { feed, cursor }
153
151
  }
154
152