@atproto/bsky 0.3.13 → 0.5.0

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 (288) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/dist/api/app/bsky/actor/getProfile.d.ts.map +1 -1
  3. package/dist/api/app/bsky/actor/getProfile.js +1 -0
  4. package/dist/api/app/bsky/actor/getProfile.js.map +1 -1
  5. package/dist/api/app/bsky/actor/getProfiles.d.ts.map +1 -1
  6. package/dist/api/app/bsky/actor/getProfiles.js +1 -0
  7. package/dist/api/app/bsky/actor/getProfiles.js.map +1 -1
  8. package/dist/api/app/bsky/actor/getSuggestions.d.ts.map +1 -1
  9. package/dist/api/app/bsky/actor/getSuggestions.js +1 -0
  10. package/dist/api/app/bsky/actor/getSuggestions.js.map +1 -1
  11. package/dist/api/app/bsky/actor/searchActors.d.ts.map +1 -1
  12. package/dist/api/app/bsky/actor/searchActors.js +1 -0
  13. package/dist/api/app/bsky/actor/searchActors.js.map +1 -1
  14. package/dist/api/app/bsky/actor/searchActorsTypeahead.d.ts.map +1 -1
  15. package/dist/api/app/bsky/actor/searchActorsTypeahead.js +1 -0
  16. package/dist/api/app/bsky/actor/searchActorsTypeahead.js.map +1 -1
  17. package/dist/api/app/bsky/bookmark/getBookmarks.d.ts.map +1 -1
  18. package/dist/api/app/bsky/bookmark/getBookmarks.js +1 -0
  19. package/dist/api/app/bsky/bookmark/getBookmarks.js.map +1 -1
  20. package/dist/api/app/bsky/contact/getMatches.d.ts.map +1 -1
  21. package/dist/api/app/bsky/contact/getMatches.js +1 -0
  22. package/dist/api/app/bsky/contact/getMatches.js.map +1 -1
  23. package/dist/api/app/bsky/contact/importContacts.d.ts.map +1 -1
  24. package/dist/api/app/bsky/contact/importContacts.js +1 -0
  25. package/dist/api/app/bsky/contact/importContacts.js.map +1 -1
  26. package/dist/api/app/bsky/feed/getActorFeeds.d.ts.map +1 -1
  27. package/dist/api/app/bsky/feed/getActorFeeds.js +5 -1
  28. package/dist/api/app/bsky/feed/getActorFeeds.js.map +1 -1
  29. package/dist/api/app/bsky/feed/getActorLikes.d.ts.map +1 -1
  30. package/dist/api/app/bsky/feed/getActorLikes.js +1 -0
  31. package/dist/api/app/bsky/feed/getActorLikes.js.map +1 -1
  32. package/dist/api/app/bsky/feed/getAuthorFeed.d.ts.map +1 -1
  33. package/dist/api/app/bsky/feed/getAuthorFeed.js +1 -0
  34. package/dist/api/app/bsky/feed/getAuthorFeed.js.map +1 -1
  35. package/dist/api/app/bsky/feed/getFeed.d.ts.map +1 -1
  36. package/dist/api/app/bsky/feed/getFeed.js +1 -0
  37. package/dist/api/app/bsky/feed/getFeed.js.map +1 -1
  38. package/dist/api/app/bsky/feed/getFeedGenerator.d.ts.map +1 -1
  39. package/dist/api/app/bsky/feed/getFeedGenerator.js +5 -1
  40. package/dist/api/app/bsky/feed/getFeedGenerator.js.map +1 -1
  41. package/dist/api/app/bsky/feed/getFeedGenerators.d.ts.map +1 -1
  42. package/dist/api/app/bsky/feed/getFeedGenerators.js +5 -1
  43. package/dist/api/app/bsky/feed/getFeedGenerators.js.map +1 -1
  44. package/dist/api/app/bsky/feed/getLikes.d.ts.map +1 -1
  45. package/dist/api/app/bsky/feed/getLikes.js +1 -0
  46. package/dist/api/app/bsky/feed/getLikes.js.map +1 -1
  47. package/dist/api/app/bsky/feed/getListFeed.d.ts.map +1 -1
  48. package/dist/api/app/bsky/feed/getListFeed.js +1 -0
  49. package/dist/api/app/bsky/feed/getListFeed.js.map +1 -1
  50. package/dist/api/app/bsky/feed/getPostThread.d.ts.map +1 -1
  51. package/dist/api/app/bsky/feed/getPostThread.js +1 -0
  52. package/dist/api/app/bsky/feed/getPostThread.js.map +1 -1
  53. package/dist/api/app/bsky/feed/getPosts.d.ts.map +1 -1
  54. package/dist/api/app/bsky/feed/getPosts.js +5 -1
  55. package/dist/api/app/bsky/feed/getPosts.js.map +1 -1
  56. package/dist/api/app/bsky/feed/getQuotes.d.ts.map +1 -1
  57. package/dist/api/app/bsky/feed/getQuotes.js +1 -0
  58. package/dist/api/app/bsky/feed/getQuotes.js.map +1 -1
  59. package/dist/api/app/bsky/feed/getRepostedBy.d.ts.map +1 -1
  60. package/dist/api/app/bsky/feed/getRepostedBy.js +1 -0
  61. package/dist/api/app/bsky/feed/getRepostedBy.js.map +1 -1
  62. package/dist/api/app/bsky/feed/getSuggestedFeeds.d.ts.map +1 -1
  63. package/dist/api/app/bsky/feed/getSuggestedFeeds.js +5 -1
  64. package/dist/api/app/bsky/feed/getSuggestedFeeds.js.map +1 -1
  65. package/dist/api/app/bsky/feed/getTimeline.d.ts.map +1 -1
  66. package/dist/api/app/bsky/feed/getTimeline.js +1 -0
  67. package/dist/api/app/bsky/feed/getTimeline.js.map +1 -1
  68. package/dist/api/app/bsky/feed/searchPosts.d.ts.map +1 -1
  69. package/dist/api/app/bsky/feed/searchPosts.js +1 -0
  70. package/dist/api/app/bsky/feed/searchPosts.js.map +1 -1
  71. package/dist/api/app/bsky/feed/searchPostsV2.d.ts.map +1 -1
  72. package/dist/api/app/bsky/feed/searchPostsV2.js +1 -0
  73. package/dist/api/app/bsky/feed/searchPostsV2.js.map +1 -1
  74. package/dist/api/app/bsky/graph/getActorStarterPacks.d.ts.map +1 -1
  75. package/dist/api/app/bsky/graph/getActorStarterPacks.js +1 -0
  76. package/dist/api/app/bsky/graph/getActorStarterPacks.js.map +1 -1
  77. package/dist/api/app/bsky/graph/getBlocks.d.ts.map +1 -1
  78. package/dist/api/app/bsky/graph/getBlocks.js +5 -1
  79. package/dist/api/app/bsky/graph/getBlocks.js.map +1 -1
  80. package/dist/api/app/bsky/graph/getFollowers.d.ts.map +1 -1
  81. package/dist/api/app/bsky/graph/getFollowers.js +1 -0
  82. package/dist/api/app/bsky/graph/getFollowers.js.map +1 -1
  83. package/dist/api/app/bsky/graph/getFollows.d.ts.map +1 -1
  84. package/dist/api/app/bsky/graph/getFollows.js +1 -0
  85. package/dist/api/app/bsky/graph/getFollows.js.map +1 -1
  86. package/dist/api/app/bsky/graph/getKnownFollowers.d.ts.map +1 -1
  87. package/dist/api/app/bsky/graph/getKnownFollowers.js +1 -0
  88. package/dist/api/app/bsky/graph/getKnownFollowers.js.map +1 -1
  89. package/dist/api/app/bsky/graph/getList.d.ts.map +1 -1
  90. package/dist/api/app/bsky/graph/getList.js +1 -0
  91. package/dist/api/app/bsky/graph/getList.js.map +1 -1
  92. package/dist/api/app/bsky/graph/getListBlocks.d.ts.map +1 -1
  93. package/dist/api/app/bsky/graph/getListBlocks.js +5 -1
  94. package/dist/api/app/bsky/graph/getListBlocks.js.map +1 -1
  95. package/dist/api/app/bsky/graph/getListMutes.d.ts.map +1 -1
  96. package/dist/api/app/bsky/graph/getListMutes.js +5 -1
  97. package/dist/api/app/bsky/graph/getListMutes.js.map +1 -1
  98. package/dist/api/app/bsky/graph/getLists.d.ts.map +1 -1
  99. package/dist/api/app/bsky/graph/getLists.js +1 -0
  100. package/dist/api/app/bsky/graph/getLists.js.map +1 -1
  101. package/dist/api/app/bsky/graph/getListsWithMembership.d.ts.map +1 -1
  102. package/dist/api/app/bsky/graph/getListsWithMembership.js +1 -0
  103. package/dist/api/app/bsky/graph/getListsWithMembership.js.map +1 -1
  104. package/dist/api/app/bsky/graph/getMutes.d.ts.map +1 -1
  105. package/dist/api/app/bsky/graph/getMutes.js +5 -1
  106. package/dist/api/app/bsky/graph/getMutes.js.map +1 -1
  107. package/dist/api/app/bsky/graph/getStarterPack.d.ts.map +1 -1
  108. package/dist/api/app/bsky/graph/getStarterPack.js +1 -0
  109. package/dist/api/app/bsky/graph/getStarterPack.js.map +1 -1
  110. package/dist/api/app/bsky/graph/getStarterPacks.d.ts.map +1 -1
  111. package/dist/api/app/bsky/graph/getStarterPacks.js +1 -0
  112. package/dist/api/app/bsky/graph/getStarterPacks.js.map +1 -1
  113. package/dist/api/app/bsky/graph/getStarterPacksWithMembership.d.ts.map +1 -1
  114. package/dist/api/app/bsky/graph/getStarterPacksWithMembership.js +1 -0
  115. package/dist/api/app/bsky/graph/getStarterPacksWithMembership.js.map +1 -1
  116. package/dist/api/app/bsky/graph/getSuggestedFollowsByActor.d.ts.map +1 -1
  117. package/dist/api/app/bsky/graph/getSuggestedFollowsByActor.js +1 -0
  118. package/dist/api/app/bsky/graph/getSuggestedFollowsByActor.js.map +1 -1
  119. package/dist/api/app/bsky/graph/searchStarterPacks.d.ts.map +1 -1
  120. package/dist/api/app/bsky/graph/searchStarterPacks.js +1 -0
  121. package/dist/api/app/bsky/graph/searchStarterPacks.js.map +1 -1
  122. package/dist/api/app/bsky/graph/searchStarterPacksV2.d.ts.map +1 -1
  123. package/dist/api/app/bsky/graph/searchStarterPacksV2.js +1 -0
  124. package/dist/api/app/bsky/graph/searchStarterPacksV2.js.map +1 -1
  125. package/dist/api/app/bsky/labeler/getServices.d.ts.map +1 -1
  126. package/dist/api/app/bsky/labeler/getServices.js +1 -0
  127. package/dist/api/app/bsky/labeler/getServices.js.map +1 -1
  128. package/dist/api/app/bsky/notification/getGroupedNotifications.d.ts.map +1 -1
  129. package/dist/api/app/bsky/notification/getGroupedNotifications.js +41 -20
  130. package/dist/api/app/bsky/notification/getGroupedNotifications.js.map +1 -1
  131. package/dist/api/app/bsky/notification/grouping/algoGravity.d.ts +4 -3
  132. package/dist/api/app/bsky/notification/grouping/algoGravity.d.ts.map +1 -1
  133. package/dist/api/app/bsky/notification/grouping/algoGravity.js +53 -42
  134. package/dist/api/app/bsky/notification/grouping/algoGravity.js.map +1 -1
  135. package/dist/api/app/bsky/notification/grouping/algoLookback.d.ts +4 -3
  136. package/dist/api/app/bsky/notification/grouping/algoLookback.d.ts.map +1 -1
  137. package/dist/api/app/bsky/notification/grouping/algoLookback.js +56 -42
  138. package/dist/api/app/bsky/notification/grouping/algoLookback.js.map +1 -1
  139. package/dist/api/app/bsky/notification/grouping/grouping.d.ts +12 -2
  140. package/dist/api/app/bsky/notification/grouping/grouping.d.ts.map +1 -1
  141. package/dist/api/app/bsky/notification/grouping/grouping.js +20 -6
  142. package/dist/api/app/bsky/notification/grouping/grouping.js.map +1 -1
  143. package/dist/api/app/bsky/notification/grouping/spotlight.d.ts +2 -2
  144. package/dist/api/app/bsky/notification/grouping/spotlight.d.ts.map +1 -1
  145. package/dist/api/app/bsky/notification/grouping/spotlight.js +35 -22
  146. package/dist/api/app/bsky/notification/grouping/spotlight.js.map +1 -1
  147. package/dist/api/app/bsky/notification/listActivitySubscriptions.d.ts.map +1 -1
  148. package/dist/api/app/bsky/notification/listActivitySubscriptions.js +1 -0
  149. package/dist/api/app/bsky/notification/listActivitySubscriptions.js.map +1 -1
  150. package/dist/api/app/bsky/notification/listNotifications.d.ts.map +1 -1
  151. package/dist/api/app/bsky/notification/listNotifications.js +5 -1
  152. package/dist/api/app/bsky/notification/listNotifications.js.map +1 -1
  153. package/dist/api/app/bsky/unspecced/atmosphere-grouping.d.ts +16 -0
  154. package/dist/api/app/bsky/unspecced/atmosphere-grouping.d.ts.map +1 -0
  155. package/dist/api/app/bsky/unspecced/atmosphere-grouping.js +124 -0
  156. package/dist/api/app/bsky/unspecced/atmosphere-grouping.js.map +1 -0
  157. package/dist/api/app/bsky/unspecced/atmosphere-hydration.d.ts +32 -0
  158. package/dist/api/app/bsky/unspecced/atmosphere-hydration.d.ts.map +1 -0
  159. package/dist/api/app/bsky/unspecced/atmosphere-hydration.js +201 -0
  160. package/dist/api/app/bsky/unspecced/atmosphere-hydration.js.map +1 -0
  161. package/dist/api/app/bsky/unspecced/atmosphere-pagination.d.ts +6 -0
  162. package/dist/api/app/bsky/unspecced/atmosphere-pagination.d.ts.map +1 -0
  163. package/dist/api/app/bsky/unspecced/atmosphere-pagination.js +164 -0
  164. package/dist/api/app/bsky/unspecced/atmosphere-pagination.js.map +1 -0
  165. package/dist/api/app/bsky/unspecced/getAtmosphereExploreTab.d.ts.map +1 -1
  166. package/dist/api/app/bsky/unspecced/getAtmosphereExploreTab.js +120 -55
  167. package/dist/api/app/bsky/unspecced/getAtmosphereExploreTab.js.map +1 -1
  168. package/dist/api/app/bsky/unspecced/getAtmosphereTimeline.d.ts +4 -0
  169. package/dist/api/app/bsky/unspecced/getAtmosphereTimeline.d.ts.map +1 -0
  170. package/dist/api/app/bsky/unspecced/getAtmosphereTimeline.js +30 -0
  171. package/dist/api/app/bsky/unspecced/getAtmosphereTimeline.js.map +1 -0
  172. package/dist/api/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.d.ts.map +1 -1
  173. package/dist/api/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.js +4 -7
  174. package/dist/api/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.js.map +1 -1
  175. package/dist/api/app/bsky/unspecced/getPopularFeedGenerators.d.ts.map +1 -1
  176. package/dist/api/app/bsky/unspecced/getPopularFeedGenerators.js +1 -0
  177. package/dist/api/app/bsky/unspecced/getPopularFeedGenerators.js.map +1 -1
  178. package/dist/api/app/bsky/unspecced/getPostThreadOtherV2.d.ts.map +1 -1
  179. package/dist/api/app/bsky/unspecced/getPostThreadOtherV2.js +1 -0
  180. package/dist/api/app/bsky/unspecced/getPostThreadOtherV2.js.map +1 -1
  181. package/dist/api/app/bsky/unspecced/getPostThreadV2.d.ts.map +1 -1
  182. package/dist/api/app/bsky/unspecced/getPostThreadV2.js +1 -0
  183. package/dist/api/app/bsky/unspecced/getPostThreadV2.js.map +1 -1
  184. package/dist/api/app/bsky/unspecced/getSuggestedFeeds.d.ts.map +1 -1
  185. package/dist/api/app/bsky/unspecced/getSuggestedFeeds.js +4 -7
  186. package/dist/api/app/bsky/unspecced/getSuggestedFeeds.js.map +1 -1
  187. package/dist/api/app/bsky/unspecced/getSuggestedOnboardingUsers.d.ts.map +1 -1
  188. package/dist/api/app/bsky/unspecced/getSuggestedOnboardingUsers.js +1 -0
  189. package/dist/api/app/bsky/unspecced/getSuggestedOnboardingUsers.js.map +1 -1
  190. package/dist/api/app/bsky/unspecced/getSuggestedStarterPacks.d.ts.map +1 -1
  191. package/dist/api/app/bsky/unspecced/getSuggestedStarterPacks.js +4 -7
  192. package/dist/api/app/bsky/unspecced/getSuggestedStarterPacks.js.map +1 -1
  193. package/dist/api/app/bsky/unspecced/getSuggestedUsers.d.ts.map +1 -1
  194. package/dist/api/app/bsky/unspecced/getSuggestedUsers.js +2 -19
  195. package/dist/api/app/bsky/unspecced/getSuggestedUsers.js.map +1 -1
  196. package/dist/api/app/bsky/unspecced/getSuggestedUsersForDiscover.d.ts.map +1 -1
  197. package/dist/api/app/bsky/unspecced/getSuggestedUsersForDiscover.js +1 -0
  198. package/dist/api/app/bsky/unspecced/getSuggestedUsersForDiscover.js.map +1 -1
  199. package/dist/api/app/bsky/unspecced/getSuggestedUsersForExplore.d.ts.map +1 -1
  200. package/dist/api/app/bsky/unspecced/getSuggestedUsersForExplore.js +1 -0
  201. package/dist/api/app/bsky/unspecced/getSuggestedUsersForExplore.js.map +1 -1
  202. package/dist/api/app/bsky/unspecced/getSuggestedUsersForSeeMore.d.ts.map +1 -1
  203. package/dist/api/app/bsky/unspecced/getSuggestedUsersForSeeMore.js +1 -0
  204. package/dist/api/app/bsky/unspecced/getSuggestedUsersForSeeMore.js.map +1 -1
  205. package/dist/api/app/bsky/unspecced/getTrendingTopics.d.ts.map +1 -1
  206. package/dist/api/app/bsky/unspecced/getTrendingTopics.js +6 -2
  207. package/dist/api/app/bsky/unspecced/getTrendingTopics.js.map +1 -1
  208. package/dist/api/app/bsky/unspecced/getTrends.d.ts.map +1 -1
  209. package/dist/api/app/bsky/unspecced/getTrends.js +6 -2
  210. package/dist/api/app/bsky/unspecced/getTrends.js.map +1 -1
  211. package/dist/api/blob-resolver.d.ts.map +1 -1
  212. package/dist/api/blob-resolver.js +9 -8
  213. package/dist/api/blob-resolver.js.map +1 -1
  214. package/dist/api/index.d.ts.map +1 -1
  215. package/dist/api/index.js +2 -0
  216. package/dist/api/index.js.map +1 -1
  217. package/dist/api/internal/bsky/actor/getProfiles.d.ts.map +1 -1
  218. package/dist/api/internal/bsky/actor/getProfiles.js +1 -0
  219. package/dist/api/internal/bsky/actor/getProfiles.js.map +1 -1
  220. package/dist/config.d.ts +2 -6
  221. package/dist/config.d.ts.map +1 -1
  222. package/dist/config.js +7 -16
  223. package/dist/config.js.map +1 -1
  224. package/dist/context.d.ts +0 -2
  225. package/dist/context.d.ts.map +1 -1
  226. package/dist/context.js +0 -3
  227. package/dist/context.js.map +1 -1
  228. package/dist/feature-gates/gates.d.ts +0 -4
  229. package/dist/feature-gates/gates.d.ts.map +1 -1
  230. package/dist/feature-gates/gates.js +0 -4
  231. package/dist/feature-gates/gates.js.map +1 -1
  232. package/dist/hydration/external.d.ts +58 -45
  233. package/dist/hydration/external.d.ts.map +1 -1
  234. package/dist/hydration/external.js +134 -114
  235. package/dist/hydration/external.js.map +1 -1
  236. package/dist/hydration/hydrator.d.ts +15 -9
  237. package/dist/hydration/hydrator.d.ts.map +1 -1
  238. package/dist/hydration/hydrator.js +170 -210
  239. package/dist/hydration/hydrator.js.map +1 -1
  240. package/dist/image/server.d.ts.map +1 -1
  241. package/dist/image/server.js +12 -1
  242. package/dist/image/server.js.map +1 -1
  243. package/dist/index.d.ts.map +1 -1
  244. package/dist/index.js +4 -19
  245. package/dist/index.js.map +1 -1
  246. package/dist/lexicons/app/bsky/unspecced/getAtmosphereExploreTab.defs.d.ts +29 -0
  247. package/dist/lexicons/app/bsky/unspecced/getAtmosphereExploreTab.defs.d.ts.map +1 -1
  248. package/dist/lexicons/app/bsky/unspecced/getAtmosphereExploreTab.defs.js +2 -1
  249. package/dist/lexicons/app/bsky/unspecced/getAtmosphereExploreTab.defs.js.map +1 -1
  250. package/dist/lexicons/app/bsky/unspecced/getAtmosphereTimeline.d.ts +3 -0
  251. package/dist/lexicons/app/bsky/unspecced/getAtmosphereTimeline.d.ts.map +1 -0
  252. package/dist/lexicons/app/bsky/unspecced/getAtmosphereTimeline.defs.d.ts +85 -0
  253. package/dist/lexicons/app/bsky/unspecced/getAtmosphereTimeline.defs.d.ts.map +1 -0
  254. package/dist/lexicons/app/bsky/unspecced/getAtmosphereTimeline.defs.js +29 -0
  255. package/dist/lexicons/app/bsky/unspecced/getAtmosphereTimeline.defs.js.map +1 -0
  256. package/dist/lexicons/app/bsky/unspecced/getAtmosphereTimeline.js +6 -0
  257. package/dist/lexicons/app/bsky/unspecced/getAtmosphereTimeline.js.map +1 -0
  258. package/dist/lexicons/app/bsky/unspecced.d.ts +1 -0
  259. package/dist/lexicons/app/bsky/unspecced.d.ts.map +1 -1
  260. package/dist/lexicons/app/bsky/unspecced.js +1 -0
  261. package/dist/lexicons/app/bsky/unspecced.js.map +1 -1
  262. package/dist/lexicons/tools/ozone/moderation/emitEvent.defs.d.ts +2 -2
  263. package/dist/lexicons/tools/ozone/moderation/emitEvent.defs.js.map +1 -1
  264. package/dist/lexicons/tools/ozone/report/closeReports.defs.d.ts +1 -1
  265. package/dist/lexicons/tools/ozone/report/closeReports.defs.d.ts.map +1 -1
  266. package/dist/lexicons/tools/ozone/report/closeReports.defs.js +1 -1
  267. package/dist/lexicons/tools/ozone/report/closeReports.defs.js.map +1 -1
  268. package/dist/telemetry/events.d.ts +14 -6
  269. package/dist/telemetry/events.d.ts.map +1 -1
  270. package/dist/telemetry/events.js +40 -5
  271. package/dist/telemetry/events.js.map +1 -1
  272. package/dist/util/external/standard-site.d.ts +2 -3
  273. package/dist/util/external/standard-site.d.ts.map +1 -1
  274. package/dist/util/external/standard-site.js +2 -3
  275. package/dist/util/external/standard-site.js.map +1 -1
  276. package/dist/util/uris.d.ts +5 -2
  277. package/dist/util/uris.d.ts.map +1 -1
  278. package/dist/util/uris.js +14 -1
  279. package/dist/util/uris.js.map +1 -1
  280. package/dist/views/external.d.ts +5 -0
  281. package/dist/views/external.d.ts.map +1 -1
  282. package/dist/views/external.js +38 -11
  283. package/dist/views/external.js.map +1 -1
  284. package/dist/views/index.d.ts +2 -2
  285. package/dist/views/index.d.ts.map +1 -1
  286. package/dist/views/index.js +17 -11
  287. package/dist/views/index.js.map +1 -1
  288. package/package.json +13 -14
@@ -1 +1 @@
1
- {"version":3,"file":"getStarterPacksWithMembership.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getStarterPacksWithMembership.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAiBxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAkCvD"}
1
+ {"version":3,"file":"getStarterPacksWithMembership.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getStarterPacksWithMembership.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAiBxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAmCvD"}
@@ -12,6 +12,7 @@ export default function (server, ctx) {
12
12
  const viewer = auth.credentials.iss;
13
13
  const labelers = ctx.reqLabelers(req);
14
14
  const hydrateCtx = await ctx.hydrator.createContext({
15
+ xrpcEndpoint: app.bsky.graph.getStarterPacksWithMembership.$lxm,
15
16
  labelers,
16
17
  viewer,
17
18
  });
@@ -1 +1 @@
1
- {"version":3,"file":"getStarterPacksWithMembership.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getStarterPacksWithMembership.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined } from '@atproto/common'\nimport type { AtUriString, DidString } from '@atproto/syntax'\nimport { InvalidRequestError, type Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport {\n type HydrateCtxWithViewer,\n type Hydrator,\n mergeManyStates,\n} from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type SkeletonFnInput,\n createPipeline,\n noRules,\n} from '../../../../pipeline.js'\nimport type { Views } from '../../../../views/index.js'\nimport { clearlyBadCursor, fillPage, resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getStarterPacksWithMembership = createPipeline(\n skeleton,\n hydration,\n noRules,\n presentation,\n )\n server.add(app.bsky.graph.getStarterPacksWithMembership, {\n auth: ctx.authVerifier.standard,\n handler: async ({ params, auth, req }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n labelers,\n viewer,\n })\n const result = await fillPage({\n cursor: params.cursor,\n limit: params.limit,\n fetch: ({ cursor, limit }) =>\n getStarterPacksWithMembership(\n { ...params, cursor, limit, hydrateCtx },\n ctx,\n ),\n items: (r) => r.starterPacksWithMembership,\n })\n\n return {\n encoding: 'application/json',\n body: result,\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n },\n })\n}\n\nconst skeleton = async (\n input: SkeletonFnInput<Context, Params>,\n): Promise<SkeletonState> => {\n const { ctx, params } = input\n const [actorDid] = await ctx.hydrator.actor.getDids([params.actor])\n if (!actorDid) throw new InvalidRequestError('Profile not found')\n\n if (clearlyBadCursor(params.cursor)) {\n return { actorDid, starterPackUris: [] }\n }\n\n const { uris: starterPackUris, cursor } =\n await ctx.hydrator.dataplane.getActorStarterPacks({\n actorDid: params.hydrateCtx.viewer,\n cursor: params.cursor,\n limit: params.limit,\n })\n\n return {\n actorDid,\n starterPackUris: starterPackUris as AtUriString[],\n cursor,\n }\n}\n\nconst hydration = async (\n input: HydrationFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, params, skeleton } = input\n const { actorDid, starterPackUris } = skeleton\n const spHydrationState = await ctx.hydrator.hydrateStarterPacks(\n starterPackUris,\n params.hydrateCtx,\n )\n const listUris = mapDefined(\n starterPackUris,\n (uri) => spHydrationState.starterPacks?.get(uri)?.record.list,\n )\n const listMembershipHydrationState =\n await ctx.hydrator.hydrateListsMembership(\n listUris,\n actorDid,\n params.hydrateCtx,\n )\n return mergeManyStates(spHydrationState, listMembershipHydrationState)\n}\n\nconst presentation = (\n input: PresentationFnInput<Context, Params, SkeletonState>,\n): app.bsky.graph.getStarterPacksWithMembership.$OutputBody => {\n const { ctx, skeleton, hydration } = input\n const { actorDid, starterPackUris, cursor } = skeleton\n\n const starterPacksWithMembership = mapDefined(starterPackUris, (spUri) => {\n const listUri = hydration.starterPacks?.get(spUri)?.record.list\n const starterPack = ctx.views.starterPack(spUri, hydration)\n if (!listUri || !starterPack) return\n\n const listItemUri = hydration.listMemberships\n ?.get(listUri)\n ?.get(actorDid)?.actorListItemUri\n\n return {\n starterPack,\n listItem: listItemUri\n ? ctx.views.listItemView(listItemUri, actorDid, hydration)\n : undefined,\n }\n })\n return { starterPacksWithMembership, cursor }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n}\n\ntype Params = app.bsky.graph.getStarterPacksWithMembership.$Params & {\n hydrateCtx: HydrateCtxWithViewer\n}\n\ntype SkeletonState = {\n actorDid: DidString\n starterPackUris: AtUriString[]\n cursor?: string\n}\n"]}
1
+ {"version":3,"file":"getStarterPacksWithMembership.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getStarterPacksWithMembership.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined } from '@atproto/common'\nimport type { AtUriString, DidString } from '@atproto/syntax'\nimport { InvalidRequestError, type Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport {\n type HydrateCtxWithViewer,\n type Hydrator,\n mergeManyStates,\n} from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type SkeletonFnInput,\n createPipeline,\n noRules,\n} from '../../../../pipeline.js'\nimport type { Views } from '../../../../views/index.js'\nimport { clearlyBadCursor, fillPage, resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getStarterPacksWithMembership = createPipeline(\n skeleton,\n hydration,\n noRules,\n presentation,\n )\n server.add(app.bsky.graph.getStarterPacksWithMembership, {\n auth: ctx.authVerifier.standard,\n handler: async ({ params, auth, req }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n xrpcEndpoint: app.bsky.graph.getStarterPacksWithMembership.$lxm,\n labelers,\n viewer,\n })\n const result = await fillPage({\n cursor: params.cursor,\n limit: params.limit,\n fetch: ({ cursor, limit }) =>\n getStarterPacksWithMembership(\n { ...params, cursor, limit, hydrateCtx },\n ctx,\n ),\n items: (r) => r.starterPacksWithMembership,\n })\n\n return {\n encoding: 'application/json',\n body: result,\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n },\n })\n}\n\nconst skeleton = async (\n input: SkeletonFnInput<Context, Params>,\n): Promise<SkeletonState> => {\n const { ctx, params } = input\n const [actorDid] = await ctx.hydrator.actor.getDids([params.actor])\n if (!actorDid) throw new InvalidRequestError('Profile not found')\n\n if (clearlyBadCursor(params.cursor)) {\n return { actorDid, starterPackUris: [] }\n }\n\n const { uris: starterPackUris, cursor } =\n await ctx.hydrator.dataplane.getActorStarterPacks({\n actorDid: params.hydrateCtx.viewer,\n cursor: params.cursor,\n limit: params.limit,\n })\n\n return {\n actorDid,\n starterPackUris: starterPackUris as AtUriString[],\n cursor,\n }\n}\n\nconst hydration = async (\n input: HydrationFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, params, skeleton } = input\n const { actorDid, starterPackUris } = skeleton\n const spHydrationState = await ctx.hydrator.hydrateStarterPacks(\n starterPackUris,\n params.hydrateCtx,\n )\n const listUris = mapDefined(\n starterPackUris,\n (uri) => spHydrationState.starterPacks?.get(uri)?.record.list,\n )\n const listMembershipHydrationState =\n await ctx.hydrator.hydrateListsMembership(\n listUris,\n actorDid,\n params.hydrateCtx,\n )\n return mergeManyStates(spHydrationState, listMembershipHydrationState)\n}\n\nconst presentation = (\n input: PresentationFnInput<Context, Params, SkeletonState>,\n): app.bsky.graph.getStarterPacksWithMembership.$OutputBody => {\n const { ctx, skeleton, hydration } = input\n const { actorDid, starterPackUris, cursor } = skeleton\n\n const starterPacksWithMembership = mapDefined(starterPackUris, (spUri) => {\n const listUri = hydration.starterPacks?.get(spUri)?.record.list\n const starterPack = ctx.views.starterPack(spUri, hydration)\n if (!listUri || !starterPack) return\n\n const listItemUri = hydration.listMemberships\n ?.get(listUri)\n ?.get(actorDid)?.actorListItemUri\n\n return {\n starterPack,\n listItem: listItemUri\n ? ctx.views.listItemView(listItemUri, actorDid, hydration)\n : undefined,\n }\n })\n return { starterPacksWithMembership, cursor }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n}\n\ntype Params = app.bsky.graph.getStarterPacksWithMembership.$Params & {\n hydrateCtx: HydrateCtxWithViewer\n}\n\ntype SkeletonState = {\n actorDid: DidString\n starterPackUris: AtUriString[]\n cursor?: string\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"getSuggestedFollowsByActor.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getSuggestedFollowsByActor.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,MAAM,EACZ,MAAM,sBAAsB,CAAA;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAcxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAwDvD"}
1
+ {"version":3,"file":"getSuggestedFollowsByActor.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getSuggestedFollowsByActor.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,MAAM,EACZ,MAAM,sBAAsB,CAAA;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAcxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAyDvD"}
@@ -12,6 +12,7 @@ export default function (server, ctx) {
12
12
  const viewer = auth.credentials.iss;
13
13
  const labelers = ctx.reqLabelers(req);
14
14
  const hydrateCtx = await ctx.hydrator.createContext({
15
+ xrpcEndpoint: app.bsky.graph.getSuggestedFollowsByActor.$lxm,
15
16
  labelers,
16
17
  viewer,
17
18
  features: ctx.featureGatesClient.scope(ctx.featureGatesClient.parseUserContextFromHandler({
@@ -1 +1 @@
1
- {"version":3,"file":"getSuggestedFollowsByActor.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getSuggestedFollowsByActor.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined, noUndefinedVals } from '@atproto/common'\nimport type { Client, DidString } from '@atproto/lex'\nimport {\n type Headers as HeadersMap,\n InternalServerError,\n InvalidRequestError,\n type Server,\n} from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport type { HydrateCtx, Hydrator } from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type RulesFnInput,\n type SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline.js'\nimport { getAtprotoPassthroughHeaders } from '../../../../util/headers.js'\nimport type { Views } from '../../../../views/index.js'\nimport { resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getSuggestedFollowsByActor = createPipeline(\n skeleton,\n hydration,\n noBlocksOrMutes,\n presentation,\n )\n server.add(app.bsky.graph.getSuggestedFollowsByActor, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ auth, params, req, signal }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n labelers,\n viewer,\n features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({\n viewer,\n req,\n }),\n ),\n })\n\n const useIris = hydrateCtx.features.checkGate(\n hydrateCtx.features.Gate.SuggestedUsersIrisEnable,\n )\n const client = useIris ? ctx.irisClient : ctx.suggestionsClient\n\n if (!client) {\n return {\n encoding: 'application/json',\n body: { suggestions: [] },\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n }\n\n const headers = noUndefinedVals({\n 'accept-language': req.headers['accept-language'],\n ...getAtprotoPassthroughHeaders(req),\n })\n\n const { contentLanguage, ...body } = await getSuggestedFollowsByActor(\n { ...params, hydrateCtx, headers, signal },\n ctx,\n )\n\n return {\n encoding: 'application/json',\n body,\n headers: {\n ...(contentLanguage ? { 'content-language': contentLanguage } : null),\n ...resHeaders({ labelers: hydrateCtx.labelers }),\n },\n }\n },\n })\n}\n\nconst skeleton = async (\n input: SkeletonFnInput<Context, Params>,\n): Promise<SkeletonState> => {\n const { params, ctx } = input\n\n const useIris = params.hydrateCtx.features.checkGate(\n params.hydrateCtx.features.Gate.SuggestedUsersIrisEnable,\n )\n const client = useIris ? ctx.irisClient : ctx.suggestionsClient\n\n // handled above already, this branch should not be reached\n if (!client) {\n throw new InternalServerError('Suggestions service not configured')\n }\n\n const [relativeToDid] = await ctx.hydrator.actor.getDids([params.actor])\n if (!relativeToDid) {\n throw new InvalidRequestError('Actor not found')\n }\n\n const res = await client.xrpc(app.bsky.unspecced.getSuggestionsSkeleton, {\n params: {\n viewer: params.hydrateCtx.viewer ?? undefined,\n relativeToDid,\n },\n headers: params.headers,\n signal: params.signal,\n })\n\n return {\n recIdStr: res.body.recIdStr,\n suggestedDids: res.body.actors.map((a) => a.did),\n contentLanguage: res.headers.get('content-language') ?? undefined,\n }\n}\n\nconst hydration = async (\n input: HydrationFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, params, skeleton } = input\n const { suggestedDids } = skeleton\n if (\n params.hydrateCtx.features.checkGate(\n params.hydrateCtx.features.Gate.SuggestedUsersSocialProofEnable,\n )\n ) {\n return ctx.hydrator.hydrateProfilesDetailed(\n suggestedDids,\n params.hydrateCtx,\n { knownFollowersDids: suggestedDids, activitySubscriptions: true },\n )\n } else {\n return ctx.hydrator.hydrateProfiles(suggestedDids, params.hydrateCtx)\n }\n}\n\nconst noBlocksOrMutes = (\n input: RulesFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, skeleton, hydration } = input\n skeleton.suggestedDids = skeleton.suggestedDids.filter(\n (did) =>\n !ctx.views.viewerBlockExists(did, hydration) &&\n !ctx.views.viewerMuteExists(did, hydration),\n )\n return skeleton\n}\n\nconst presentation = (\n input: PresentationFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, hydration, skeleton } = input\n const { suggestedDids, contentLanguage } = skeleton\n const suggestions = mapDefined(suggestedDids, (did) =>\n ctx.views.profile(did, hydration),\n )\n return {\n recIdStr: skeleton.recIdStr,\n contentLanguage,\n suggestions,\n }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n suggestionsClient: Client | undefined\n irisClient: Client | undefined\n}\n\ntype Params = app.bsky.graph.getSuggestedFollowsByActor.$Params & {\n hydrateCtx: HydrateCtx\n headers: HeadersMap\n signal: AbortSignal\n}\n\ntype SkeletonState = {\n suggestedDids: DidString[]\n recIdStr?: string\n contentLanguage?: string\n}\n"]}
1
+ {"version":3,"file":"getSuggestedFollowsByActor.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getSuggestedFollowsByActor.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined, noUndefinedVals } from '@atproto/common'\nimport type { Client, DidString } from '@atproto/lex'\nimport {\n type Headers as HeadersMap,\n InternalServerError,\n InvalidRequestError,\n type Server,\n} from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport type { HydrateCtx, Hydrator } from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type RulesFnInput,\n type SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline.js'\nimport { getAtprotoPassthroughHeaders } from '../../../../util/headers.js'\nimport type { Views } from '../../../../views/index.js'\nimport { resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getSuggestedFollowsByActor = createPipeline(\n skeleton,\n hydration,\n noBlocksOrMutes,\n presentation,\n )\n server.add(app.bsky.graph.getSuggestedFollowsByActor, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ auth, params, req, signal }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n xrpcEndpoint: app.bsky.graph.getSuggestedFollowsByActor.$lxm,\n labelers,\n viewer,\n features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({\n viewer,\n req,\n }),\n ),\n })\n\n const useIris = hydrateCtx.features.checkGate(\n hydrateCtx.features.Gate.SuggestedUsersIrisEnable,\n )\n const client = useIris ? ctx.irisClient : ctx.suggestionsClient\n\n if (!client) {\n return {\n encoding: 'application/json',\n body: { suggestions: [] },\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n }\n\n const headers = noUndefinedVals({\n 'accept-language': req.headers['accept-language'],\n ...getAtprotoPassthroughHeaders(req),\n })\n\n const { contentLanguage, ...body } = await getSuggestedFollowsByActor(\n { ...params, hydrateCtx, headers, signal },\n ctx,\n )\n\n return {\n encoding: 'application/json',\n body,\n headers: {\n ...(contentLanguage ? { 'content-language': contentLanguage } : null),\n ...resHeaders({ labelers: hydrateCtx.labelers }),\n },\n }\n },\n })\n}\n\nconst skeleton = async (\n input: SkeletonFnInput<Context, Params>,\n): Promise<SkeletonState> => {\n const { params, ctx } = input\n\n const useIris = params.hydrateCtx.features.checkGate(\n params.hydrateCtx.features.Gate.SuggestedUsersIrisEnable,\n )\n const client = useIris ? ctx.irisClient : ctx.suggestionsClient\n\n // handled above already, this branch should not be reached\n if (!client) {\n throw new InternalServerError('Suggestions service not configured')\n }\n\n const [relativeToDid] = await ctx.hydrator.actor.getDids([params.actor])\n if (!relativeToDid) {\n throw new InvalidRequestError('Actor not found')\n }\n\n const res = await client.xrpc(app.bsky.unspecced.getSuggestionsSkeleton, {\n params: {\n viewer: params.hydrateCtx.viewer ?? undefined,\n relativeToDid,\n },\n headers: params.headers,\n signal: params.signal,\n })\n\n return {\n recIdStr: res.body.recIdStr,\n suggestedDids: res.body.actors.map((a) => a.did),\n contentLanguage: res.headers.get('content-language') ?? undefined,\n }\n}\n\nconst hydration = async (\n input: HydrationFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, params, skeleton } = input\n const { suggestedDids } = skeleton\n if (\n params.hydrateCtx.features.checkGate(\n params.hydrateCtx.features.Gate.SuggestedUsersSocialProofEnable,\n )\n ) {\n return ctx.hydrator.hydrateProfilesDetailed(\n suggestedDids,\n params.hydrateCtx,\n { knownFollowersDids: suggestedDids, activitySubscriptions: true },\n )\n } else {\n return ctx.hydrator.hydrateProfiles(suggestedDids, params.hydrateCtx)\n }\n}\n\nconst noBlocksOrMutes = (\n input: RulesFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, skeleton, hydration } = input\n skeleton.suggestedDids = skeleton.suggestedDids.filter(\n (did) =>\n !ctx.views.viewerBlockExists(did, hydration) &&\n !ctx.views.viewerMuteExists(did, hydration),\n )\n return skeleton\n}\n\nconst presentation = (\n input: PresentationFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, hydration, skeleton } = input\n const { suggestedDids, contentLanguage } = skeleton\n const suggestions = mapDefined(suggestedDids, (did) =>\n ctx.views.profile(did, hydration),\n )\n return {\n recIdStr: skeleton.recIdStr,\n contentLanguage,\n suggestions,\n }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n suggestionsClient: Client | undefined\n irisClient: Client | undefined\n}\n\ntype Params = app.bsky.graph.getSuggestedFollowsByActor.$Params & {\n hydrateCtx: HydrateCtx\n headers: HeadersMap\n signal: AbortSignal\n}\n\ntype SkeletonState = {\n suggestedDids: DidString[]\n recIdStr?: string\n contentLanguage?: string\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"searchStarterPacks.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/searchStarterPacks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAmBxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAiDvD"}
1
+ {"version":3,"file":"searchStarterPacks.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/searchStarterPacks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAmBxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAkDvD"}
@@ -13,6 +13,7 @@ export default function (server, ctx) {
13
13
  const { viewer, includeTakedowns, skipViewerBlocks } = ctx.authVerifier.parseCreds(auth);
14
14
  const labelers = ctx.reqLabelers(req);
15
15
  const hydrateCtx = await ctx.hydrator.createContext({
16
+ xrpcEndpoint: app.bsky.graph.searchStarterPacks.$lxm,
16
17
  viewer,
17
18
  labelers,
18
19
  includeTakedowns,
@@ -1 +1 @@
1
- {"version":3,"file":"searchStarterPacks.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/searchStarterPacks.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined } from '@atproto/common'\nimport type { AtUriString, Client } from '@atproto/lex'\nimport type { Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport {\n type DataPlaneClient,\n asInvalidRequest,\n} from '../../../../data-plane/index.js'\nimport type { HydrateCtx, Hydrator } from '../../../../hydration/hydrator.js'\nimport { parseString } from '../../../../hydration/util.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type RulesFnInput,\n type SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline.js'\nimport { uriToDid as creatorFromUri } from '../../../../util/uris.js'\nimport type { Views } from '../../../../views/index.js'\nimport { fillPage, resHeaders, resolveSearchV2Override } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const searchStarterPacks = createPipeline(\n skeleton,\n hydration,\n noBlocks,\n presentation,\n )\n server.add(app.bsky.graph.searchStarterPacks, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ auth, params, req, signal }) => {\n const { viewer, includeTakedowns, skipViewerBlocks } =\n ctx.authVerifier.parseCreds(auth)\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n viewer,\n labelers,\n includeTakedowns,\n skipViewerBlocks,\n features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({\n viewer,\n req,\n }),\n ),\n })\n const results = await fillPage({\n cursor: params.cursor,\n limit: params.limit,\n fetch: ({ cursor, limit }) =>\n searchStarterPacks(\n {\n ...params,\n cursor,\n limit,\n hydrateCtx,\n signal,\n isV2Override: resolveSearchV2Override(req, ctx.cfg),\n },\n ctx,\n ),\n items: (r) => r.starterPacks,\n })\n return {\n encoding: 'application/json',\n body: results,\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n },\n })\n}\n\nconst skeletonV1 = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n const { ctx, params } = inputs\n const { q } = params\n\n if (ctx.searchClient) {\n // @NOTE cursors won't change on appview swap\n const res = await ctx.searchClient.call(\n app.bsky.unspecced.searchStarterPacksSkeleton,\n {\n q,\n cursor: params.cursor,\n limit: params.limit,\n viewer: params.hydrateCtx.viewer ?? undefined,\n },\n { signal: params.signal },\n )\n return {\n uris: res.starterPacks.map(({ uri }) => uri),\n cursor: parseString(res.cursor),\n }\n }\n\n const res = await ctx.dataplane.searchStarterPacks({\n term: q,\n limit: params.limit,\n cursor: params.cursor,\n })\n return {\n uris: res.uris as AtUriString[],\n cursor: parseString(res.cursor),\n }\n}\n\nconst skeletonV2 = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n const { ctx, params } = inputs\n const { q } = params\n\n // Surface dataplane InvalidArgument errors as a 400 rather than a 500.\n const res = await ctx.dataplane\n .searchStarterPacksV2({\n params: {\n query: q,\n viewer: params.hydrateCtx.viewer ?? undefined,\n limit: params.limit,\n cursor: params.cursor,\n },\n })\n .catch(asInvalidRequest())\n return {\n uris: res.starterPacks.map(({ uri }) => uri as AtUriString),\n cursor: parseString(res.pageInfo?.cursor),\n }\n}\n\nconst skeleton = async (input: SkeletonFnInput<Context, Params>) => {\n const useV2 =\n input.params.hydrateCtx.features.checkGate(\n input.params.hydrateCtx.features.Gate.SearchV2Enable,\n ) || input.params.isV2Override\n const skeletonFn = useV2 ? skeletonV2 : skeletonV1\n return skeletonFn(input)\n}\n\nconst hydration = async (\n inputs: HydrationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, params, skeleton } = inputs\n return ctx.hydrator.hydrateStarterPacksBasic(skeleton.uris, params.hydrateCtx)\n}\n\nconst noBlocks = (inputs: RulesFnInput<Context, Params, Skeleton>) => {\n const { ctx, skeleton, hydration } = inputs\n skeleton.uris = skeleton.uris.filter((uri) => {\n const creator = creatorFromUri(uri)\n return !ctx.views.viewerBlockExists(creator, hydration)\n })\n return skeleton\n}\n\nconst presentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, skeleton, hydration } = inputs\n const starterPacks = mapDefined(skeleton.uris, (uri) =>\n ctx.views.starterPackBasic(uri, hydration),\n )\n return {\n starterPacks: starterPacks,\n cursor: skeleton.cursor,\n }\n}\n\ntype Context = {\n dataplane: DataPlaneClient\n hydrator: Hydrator\n views: Views\n searchClient?: Client\n}\n\ntype Params = app.bsky.graph.searchStarterPacks.$Params & {\n hydrateCtx: HydrateCtx\n signal: AbortSignal\n isV2Override: boolean\n}\n\ntype Skeleton = {\n uris: AtUriString[]\n cursor?: string\n}\n"]}
1
+ {"version":3,"file":"searchStarterPacks.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/searchStarterPacks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAI5C,OAAO,EAEL,gBAAgB,GACjB,MAAM,iCAAiC,CAAA;AAExC,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAC3D,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAKL,cAAc,GACf,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAErE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAA;AAEhF,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,kBAAkB,GAAG,cAAc,CACvC,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAY,CACb,CAAA;IACD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,EAAE;QAC5C,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,gBAAgB;QACvC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;YAC/C,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,GAClD,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YACnC,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;YACrC,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC;gBAClD,YAAY,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,IAAI;gBACpD,MAAM;gBACN,QAAQ;gBACR,gBAAgB;gBAChB,gBAAgB;gBAChB,QAAQ,EAAE,GAAG,CAAC,kBAAkB,CAAC,KAAK,CACpC,GAAG,CAAC,kBAAkB,CAAC,2BAA2B,CAAC;oBACjD,MAAM;oBACN,GAAG;iBACJ,CAAC,CACH;aACF,CAAC,CAAA;YACF,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC;gBAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAC3B,kBAAkB,CAChB;oBACE,GAAG,MAAM;oBACT,MAAM;oBACN,KAAK;oBACL,UAAU;oBACV,MAAM;oBACN,YAAY,EAAE,uBAAuB,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC;iBACpD,EACD,GAAG,CACJ;gBACH,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY;aAC7B,CAAC,CAAA;YACF,OAAO;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,OAAO;gBACb,OAAO,EAAE,UAAU,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC;aACvD,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,GAAG,KAAK,EACtB,MAAwC,EACrB,EAAE;IACrB,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;IAC9B,MAAM,EAAE,CAAC,EAAE,GAAG,MAAM,CAAA;IAEpB,IAAI,GAAG,CAAC,YAAY,EAAE,CAAC;QACrB,6CAA6C;QAC7C,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,IAAI,CACrC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,0BAA0B,EAC7C;YACE,CAAC;YACD,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM,IAAI,SAAS;SAC9C,EACD,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAC1B,CAAA;QACD,OAAO;YACL,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC;YAC5C,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC;SAChC,CAAA;IACH,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,kBAAkB,CAAC;QACjD,IAAI,EAAE,CAAC;QACP,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC,CAAA;IACF,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAqB;QAC/B,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC;KAChC,CAAA;AACH,CAAC,CAAA;AAED,MAAM,UAAU,GAAG,KAAK,EACtB,MAAwC,EACrB,EAAE;IACrB,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;IAC9B,MAAM,EAAE,CAAC,EAAE,GAAG,MAAM,CAAA;IAEpB,uEAAuE;IACvE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,SAAS;SAC5B,oBAAoB,CAAC;QACpB,MAAM,EAAE;YACN,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM,IAAI,SAAS;YAC7C,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB;KACF,CAAC;SACD,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAA;IAC5B,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,GAAkB,CAAC;QAC3D,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC;KAC1C,CAAA;AACH,CAAC,CAAA;AAED,MAAM,QAAQ,GAAG,KAAK,EAAE,KAAuC,EAAE,EAAE;IACjE,MAAM,KAAK,GACT,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CACxC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,CACrD,IAAI,KAAK,CAAC,MAAM,CAAC,YAAY,CAAA;IAChC,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAA;IAClD,OAAO,UAAU,CAAC,KAAK,CAAC,CAAA;AAC1B,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,KAAK,EACrB,MAAmD,EACnD,EAAE;IACF,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAA;IACxC,OAAO,GAAG,CAAC,QAAQ,CAAC,wBAAwB,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;AAChF,CAAC,CAAA;AAED,MAAM,QAAQ,GAAG,CAAC,MAA+C,EAAE,EAAE;IACnE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,CAAA;IAC3C,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE;QAC3C,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,CAAA;QACnC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IACF,OAAO,QAAQ,CAAA;AACjB,CAAC,CAAA;AAED,MAAM,YAAY,GAAG,CACnB,MAAsD,EACtD,EAAE;IACF,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,CAAA;IAC3C,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CACrD,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,EAAE,SAAS,CAAC,CAC3C,CAAA;IACD,OAAO;QACL,YAAY,EAAE,YAAY;QAC1B,MAAM,EAAE,QAAQ,CAAC,MAAM;KACxB,CAAA;AACH,CAAC,CAAA","sourcesContent":["import { mapDefined } from '@atproto/common'\nimport type { AtUriString, Client } from '@atproto/lex'\nimport type { Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport {\n type DataPlaneClient,\n asInvalidRequest,\n} from '../../../../data-plane/index.js'\nimport type { HydrateCtx, Hydrator } from '../../../../hydration/hydrator.js'\nimport { parseString } from '../../../../hydration/util.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type RulesFnInput,\n type SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline.js'\nimport { uriToDid as creatorFromUri } from '../../../../util/uris.js'\nimport type { Views } from '../../../../views/index.js'\nimport { fillPage, resHeaders, resolveSearchV2Override } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const searchStarterPacks = createPipeline(\n skeleton,\n hydration,\n noBlocks,\n presentation,\n )\n server.add(app.bsky.graph.searchStarterPacks, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ auth, params, req, signal }) => {\n const { viewer, includeTakedowns, skipViewerBlocks } =\n ctx.authVerifier.parseCreds(auth)\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n xrpcEndpoint: app.bsky.graph.searchStarterPacks.$lxm,\n viewer,\n labelers,\n includeTakedowns,\n skipViewerBlocks,\n features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({\n viewer,\n req,\n }),\n ),\n })\n const results = await fillPage({\n cursor: params.cursor,\n limit: params.limit,\n fetch: ({ cursor, limit }) =>\n searchStarterPacks(\n {\n ...params,\n cursor,\n limit,\n hydrateCtx,\n signal,\n isV2Override: resolveSearchV2Override(req, ctx.cfg),\n },\n ctx,\n ),\n items: (r) => r.starterPacks,\n })\n return {\n encoding: 'application/json',\n body: results,\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n },\n })\n}\n\nconst skeletonV1 = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n const { ctx, params } = inputs\n const { q } = params\n\n if (ctx.searchClient) {\n // @NOTE cursors won't change on appview swap\n const res = await ctx.searchClient.call(\n app.bsky.unspecced.searchStarterPacksSkeleton,\n {\n q,\n cursor: params.cursor,\n limit: params.limit,\n viewer: params.hydrateCtx.viewer ?? undefined,\n },\n { signal: params.signal },\n )\n return {\n uris: res.starterPacks.map(({ uri }) => uri),\n cursor: parseString(res.cursor),\n }\n }\n\n const res = await ctx.dataplane.searchStarterPacks({\n term: q,\n limit: params.limit,\n cursor: params.cursor,\n })\n return {\n uris: res.uris as AtUriString[],\n cursor: parseString(res.cursor),\n }\n}\n\nconst skeletonV2 = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n const { ctx, params } = inputs\n const { q } = params\n\n // Surface dataplane InvalidArgument errors as a 400 rather than a 500.\n const res = await ctx.dataplane\n .searchStarterPacksV2({\n params: {\n query: q,\n viewer: params.hydrateCtx.viewer ?? undefined,\n limit: params.limit,\n cursor: params.cursor,\n },\n })\n .catch(asInvalidRequest())\n return {\n uris: res.starterPacks.map(({ uri }) => uri as AtUriString),\n cursor: parseString(res.pageInfo?.cursor),\n }\n}\n\nconst skeleton = async (input: SkeletonFnInput<Context, Params>) => {\n const useV2 =\n input.params.hydrateCtx.features.checkGate(\n input.params.hydrateCtx.features.Gate.SearchV2Enable,\n ) || input.params.isV2Override\n const skeletonFn = useV2 ? skeletonV2 : skeletonV1\n return skeletonFn(input)\n}\n\nconst hydration = async (\n inputs: HydrationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, params, skeleton } = inputs\n return ctx.hydrator.hydrateStarterPacksBasic(skeleton.uris, params.hydrateCtx)\n}\n\nconst noBlocks = (inputs: RulesFnInput<Context, Params, Skeleton>) => {\n const { ctx, skeleton, hydration } = inputs\n skeleton.uris = skeleton.uris.filter((uri) => {\n const creator = creatorFromUri(uri)\n return !ctx.views.viewerBlockExists(creator, hydration)\n })\n return skeleton\n}\n\nconst presentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, skeleton, hydration } = inputs\n const starterPacks = mapDefined(skeleton.uris, (uri) =>\n ctx.views.starterPackBasic(uri, hydration),\n )\n return {\n starterPacks: starterPacks,\n cursor: skeleton.cursor,\n }\n}\n\ntype Context = {\n dataplane: DataPlaneClient\n hydrator: Hydrator\n views: Views\n searchClient?: Client\n}\n\ntype Params = app.bsky.graph.searchStarterPacks.$Params & {\n hydrateCtx: HydrateCtx\n signal: AbortSignal\n isV2Override: boolean\n}\n\ntype Skeleton = {\n uris: AtUriString[]\n cursor?: string\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"searchStarterPacksV2.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/searchStarterPacksV2.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAmBxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAwCvD"}
1
+ {"version":3,"file":"searchStarterPacksV2.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/searchStarterPacksV2.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAmBxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAyCvD"}
@@ -13,6 +13,7 @@ export default function (server, ctx) {
13
13
  const { viewer, includeTakedowns, skipViewerBlocks } = ctx.authVerifier.parseCreds(auth);
14
14
  const labelers = ctx.reqLabelers(req);
15
15
  const hydrateCtx = await ctx.hydrator.createContext({
16
+ xrpcEndpoint: app.bsky.graph.searchStarterPacksV2.$lxm,
16
17
  viewer,
17
18
  labelers,
18
19
  includeTakedowns,
@@ -1 +1 @@
1
- {"version":3,"file":"searchStarterPacksV2.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/searchStarterPacksV2.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined } from '@atproto/common'\nimport type { AtUriString } from '@atproto/lex'\nimport type { Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport {\n type DataPlaneClient,\n asInvalidRequest,\n} from '../../../../data-plane/index.js'\nimport type { HydrateCtx, Hydrator } from '../../../../hydration/hydrator.js'\nimport { parseString } from '../../../../hydration/util.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type RulesFnInput,\n type SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline.js'\nimport { uriToDid as creatorFromUri } from '../../../../util/uris.js'\nimport type { Views } from '../../../../views/index.js'\nimport { fillPage, resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const searchStarterPacksV2 = createPipeline(\n skeleton,\n hydration,\n noBlocks,\n presentation,\n )\n server.add(app.bsky.graph.searchStarterPacksV2, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ auth, params, req }) => {\n const { viewer, includeTakedowns, skipViewerBlocks } =\n ctx.authVerifier.parseCreds(auth)\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n viewer,\n labelers,\n includeTakedowns,\n skipViewerBlocks,\n features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({\n viewer,\n req,\n }),\n ),\n })\n\n const results = await fillPage({\n cursor: params.cursor,\n limit: params.limit,\n fetch: ({ cursor, limit }) =>\n searchStarterPacksV2({ ...params, cursor, limit, hydrateCtx }, ctx),\n items: (r) => r.starterPacks,\n })\n return {\n encoding: 'application/json',\n body: results,\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n },\n })\n}\n\nconst skeleton = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n const { ctx, params } = inputs\n const { q } = params\n\n // Surface dataplane InvalidArgument errors as a 400 rather than a 500.\n const res = await ctx.dataplane\n .searchStarterPacksV2({\n params: {\n query: q,\n viewer: params.hydrateCtx.viewer ?? undefined,\n limit: params.limit,\n cursor: params.cursor,\n },\n })\n .catch(asInvalidRequest())\n return {\n uris: res.starterPacks.map(({ uri }) => uri as AtUriString),\n cursor: parseString(res.pageInfo?.cursor),\n hitsTotal:\n res.pageInfo?.hitsTotal != null\n ? Number(res.pageInfo.hitsTotal)\n : undefined,\n }\n}\n\nconst hydration = async (\n inputs: HydrationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, params, skeleton } = inputs\n return ctx.hydrator.hydrateStarterPacks(skeleton.uris, params.hydrateCtx)\n}\n\nconst noBlocks = (inputs: RulesFnInput<Context, Params, Skeleton>) => {\n const { ctx, skeleton, hydration } = inputs\n skeleton.uris = skeleton.uris.filter((uri) => {\n const creator = creatorFromUri(uri)\n return !ctx.views.viewerBlockExists(creator, hydration)\n })\n return skeleton\n}\n\nconst presentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, skeleton, hydration } = inputs\n const starterPacks = mapDefined(skeleton.uris, (uri) =>\n ctx.views.starterPack(uri, hydration),\n )\n return {\n starterPacks,\n cursor: skeleton.cursor,\n hitsTotal: skeleton.hitsTotal,\n }\n}\n\ntype Context = {\n dataplane: DataPlaneClient\n hydrator: Hydrator\n views: Views\n}\n\ntype Params = app.bsky.graph.searchStarterPacksV2.$Params & {\n hydrateCtx: HydrateCtx\n}\n\ntype Skeleton = {\n uris: AtUriString[]\n cursor?: string\n hitsTotal?: number\n}\n"]}
1
+ {"version":3,"file":"searchStarterPacksV2.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/searchStarterPacksV2.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined } from '@atproto/common'\nimport type { AtUriString } from '@atproto/lex'\nimport type { Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport {\n type DataPlaneClient,\n asInvalidRequest,\n} from '../../../../data-plane/index.js'\nimport type { HydrateCtx, Hydrator } from '../../../../hydration/hydrator.js'\nimport { parseString } from '../../../../hydration/util.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type RulesFnInput,\n type SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline.js'\nimport { uriToDid as creatorFromUri } from '../../../../util/uris.js'\nimport type { Views } from '../../../../views/index.js'\nimport { fillPage, resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const searchStarterPacksV2 = createPipeline(\n skeleton,\n hydration,\n noBlocks,\n presentation,\n )\n server.add(app.bsky.graph.searchStarterPacksV2, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ auth, params, req }) => {\n const { viewer, includeTakedowns, skipViewerBlocks } =\n ctx.authVerifier.parseCreds(auth)\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n xrpcEndpoint: app.bsky.graph.searchStarterPacksV2.$lxm,\n viewer,\n labelers,\n includeTakedowns,\n skipViewerBlocks,\n features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({\n viewer,\n req,\n }),\n ),\n })\n\n const results = await fillPage({\n cursor: params.cursor,\n limit: params.limit,\n fetch: ({ cursor, limit }) =>\n searchStarterPacksV2({ ...params, cursor, limit, hydrateCtx }, ctx),\n items: (r) => r.starterPacks,\n })\n return {\n encoding: 'application/json',\n body: results,\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n },\n })\n}\n\nconst skeleton = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n const { ctx, params } = inputs\n const { q } = params\n\n // Surface dataplane InvalidArgument errors as a 400 rather than a 500.\n const res = await ctx.dataplane\n .searchStarterPacksV2({\n params: {\n query: q,\n viewer: params.hydrateCtx.viewer ?? undefined,\n limit: params.limit,\n cursor: params.cursor,\n },\n })\n .catch(asInvalidRequest())\n return {\n uris: res.starterPacks.map(({ uri }) => uri as AtUriString),\n cursor: parseString(res.pageInfo?.cursor),\n hitsTotal:\n res.pageInfo?.hitsTotal != null\n ? Number(res.pageInfo.hitsTotal)\n : undefined,\n }\n}\n\nconst hydration = async (\n inputs: HydrationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, params, skeleton } = inputs\n return ctx.hydrator.hydrateStarterPacks(skeleton.uris, params.hydrateCtx)\n}\n\nconst noBlocks = (inputs: RulesFnInput<Context, Params, Skeleton>) => {\n const { ctx, skeleton, hydration } = inputs\n skeleton.uris = skeleton.uris.filter((uri) => {\n const creator = creatorFromUri(uri)\n return !ctx.views.viewerBlockExists(creator, hydration)\n })\n return skeleton\n}\n\nconst presentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, skeleton, hydration } = inputs\n const starterPacks = mapDefined(skeleton.uris, (uri) =>\n ctx.views.starterPack(uri, hydration),\n )\n return {\n starterPacks,\n cursor: skeleton.cursor,\n hitsTotal: skeleton.hitsTotal,\n }\n}\n\ntype Context = {\n dataplane: DataPlaneClient\n hydrator: Hydrator\n views: Views\n}\n\ntype Params = app.bsky.graph.searchStarterPacksV2.$Params & {\n hydrateCtx: HydrateCtx\n}\n\ntype Skeleton = {\n uris: AtUriString[]\n cursor?: string\n hitsTotal?: number\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"getServices.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/labeler/getServices.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAIxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAkCvD"}
1
+ {"version":3,"file":"getServices.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/labeler/getServices.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAIxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAmCvD"}
@@ -9,6 +9,7 @@ export default function (server, ctx) {
9
9
  const viewer = auth.credentials.iss;
10
10
  const labelers = ctx.reqLabelers(req);
11
11
  const hydrateCtx = await ctx.hydrator.createContext({
12
+ xrpcEndpoint: app.bsky.labeler.getServices.$lxm,
12
13
  viewer,
13
14
  labelers,
14
15
  });
@@ -1 +1 @@
1
- {"version":3,"file":"getServices.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/labeler/getServices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAG5C,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;QACvC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,gBAAgB;QACvC,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;YACvC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAA;YACjC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAA;YACnC,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;YACrC,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC;gBAClD,MAAM;gBACN,QAAQ;aACT,CAAC,CAAA;YACF,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;YAEtE,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE;gBACrC,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;oBACtD,IAAI,CAAC,IAAI;wBAAE,OAAM;oBACjB,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;gBAC/D,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;oBAC9C,IAAI,CAAC,IAAI;wBAAE,OAAM;oBACjB,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;gBACvD,CAAC;YACH,CAAC,CAAC,CAAA;YAEF,OAAO;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE;oBACJ,KAAK;iBACN;gBACD,OAAO,EAAE,UAAU,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC;aACvD,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { mapDefined } from '@atproto/common'\nimport type { Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport { app } from '../../../../lexicons/index.js'\nimport { resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n server.add(app.bsky.labeler.getServices, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ params, auth, req }) => {\n const { dids, detailed } = params\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n viewer,\n labelers,\n })\n const hydration = await ctx.hydrator.hydrateLabelers(dids, hydrateCtx)\n\n const views = mapDefined(dids, (did) => {\n if (detailed) {\n const view = ctx.views.labelerDetailed(did, hydration)\n if (!view) return\n return app.bsky.labeler.defs.labelerViewDetailed.$build(view)\n } else {\n const view = ctx.views.labeler(did, hydration)\n if (!view) return\n return app.bsky.labeler.defs.labelerView.$build(view)\n }\n })\n\n return {\n encoding: 'application/json',\n body: {\n views,\n },\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n },\n })\n}\n"]}
1
+ {"version":3,"file":"getServices.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/labeler/getServices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAG5C,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;QACvC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,gBAAgB;QACvC,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;YACvC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAA;YACjC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAA;YACnC,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;YACrC,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC;gBAClD,YAAY,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI;gBAC/C,MAAM;gBACN,QAAQ;aACT,CAAC,CAAA;YACF,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;YAEtE,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE;gBACrC,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;oBACtD,IAAI,CAAC,IAAI;wBAAE,OAAM;oBACjB,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;gBAC/D,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;oBAC9C,IAAI,CAAC,IAAI;wBAAE,OAAM;oBACjB,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;gBACvD,CAAC;YACH,CAAC,CAAC,CAAA;YAEF,OAAO;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE;oBACJ,KAAK;iBACN;gBACD,OAAO,EAAE,UAAU,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC;aACvD,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { mapDefined } from '@atproto/common'\nimport type { Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport { app } from '../../../../lexicons/index.js'\nimport { resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n server.add(app.bsky.labeler.getServices, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ params, auth, req }) => {\n const { dids, detailed } = params\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n xrpcEndpoint: app.bsky.labeler.getServices.$lxm,\n viewer,\n labelers,\n })\n const hydration = await ctx.hydrator.hydrateLabelers(dids, hydrateCtx)\n\n const views = mapDefined(dids, (did) => {\n if (detailed) {\n const view = ctx.views.labelerDetailed(did, hydration)\n if (!view) return\n return app.bsky.labeler.defs.labelerViewDetailed.$build(view)\n } else {\n const view = ctx.views.labeler(did, hydration)\n if (!view) return\n return app.bsky.labeler.defs.labelerView.$build(view)\n }\n })\n\n return {\n encoding: 'application/json',\n body: {\n views,\n },\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n },\n })\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"getGroupedNotifications.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/notification/getGroupedNotifications.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAElD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAuCxD,eAAO,MAAM,eAAe,iBACZ,MAAM,eACP,MAAM,gBACL,MAAM,eACP,MAAM,eACN,MAAM,KAClB,MAoBF,CAAA;AAED,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAqCvD"}
1
+ {"version":3,"file":"getGroupedNotifications.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/notification/getGroupedNotifications.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAElD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAuCxD,eAAO,MAAM,eAAe,iBACZ,MAAM,eACP,MAAM,gBACL,MAAM,eACP,MAAM,eACN,MAAM,KAClB,MAoBF,CAAA;AAED,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAsCvD"}
@@ -1,4 +1,5 @@
1
1
  import { createHash } from 'node:crypto';
2
+ import { performance } from 'node:perf_hooks';
2
3
  import { dedupeStrs, mapDefined } from '@atproto/common';
3
4
  import { asDatetimeString, } from '@atproto/lex';
4
5
  import { AtUri } from '@atproto/syntax';
@@ -9,7 +10,7 @@ import { events } from '../../../../telemetry/events.js';
9
10
  import { uriToDid } from '../../../../util/uris.js';
10
11
  import { resHeaders } from '../../../util.js';
11
12
  import { NOTIFICATION_REASON } from './constants.js';
12
- import { buildGroups, parseRawNotification, } from './grouping/grouping.js';
13
+ import { buildNotificationItem, getGroupingAlgorithm, parseRawNotification, } from './grouping/grouping.js';
13
14
  import { compareNotificationGroupsNewestFirst, isNotificationRead, } from './grouping/shared.js';
14
15
  import { buildSpotlight } from './grouping/spotlight.js';
15
16
  import { delayCursor, shouldFilterForNeedsReview, shouldFilterHiddenThreadTag, shouldFilterReplyByThreadgate, } from './util.js';
@@ -40,6 +41,7 @@ export default function (server, ctx) {
40
41
  const features = ctx.featureGatesClient.scope(ctx.featureGatesClient.parseUserContextFromHandler({ viewer, req }));
41
42
  const labelers = ctx.reqLabelers(req);
42
43
  const hydrateCtx = await ctx.hydrator.createContext({
44
+ xrpcEndpoint: app.bsky.notification.getGroupedNotifications.$lxm,
43
45
  labelers,
44
46
  viewer,
45
47
  features,
@@ -73,15 +75,21 @@ const skeleton = async (input) => {
73
75
  let groups = [];
74
76
  let nextCursor;
75
77
  let itemsFetched = 0;
78
+ let dataplaneFetches = 0;
76
79
  let rawLimit = ctx.cfg.notificationsV2MinRawLimit;
77
- for (let read = 0; read < ctx.cfg.notificationsV2MaxReads; read++) {
80
+ const algorithm = ctx.cfg.notificationsV2Algorithm;
81
+ const { createGroupBuilder, splitBursts } = getGroupingAlgorithm(algorithm);
82
+ const buildGroups = createGroupBuilder(params.limit, now, seenAt, feed);
83
+ for (let fetches = 0; fetches < ctx.cfg.notificationsV2MaxFetches; fetches++) {
78
84
  const response = await ctx.hydrator.dataplane.getNotificationsV2({
79
85
  actorDid: params.hydrateCtx.viewer,
80
86
  feed,
81
87
  cursor,
82
88
  limit: rawLimit,
83
89
  });
90
+ dataplaneFetches++;
84
91
  itemsFetched += response.notifications.length;
92
+ const firstNewItem = items.length;
85
93
  for (const notification of response.notifications) {
86
94
  const notif = parseRawNotification(notification);
87
95
  if (!notif)
@@ -98,16 +106,16 @@ const skeleton = async (input) => {
98
106
  groupingKey = NOTIFICATION_REASON.FOLLOW;
99
107
  }
100
108
  if (notif.reason === NOTIFICATION_REASON.SUBSCRIBED_POST) {
101
- groupingKey = actorDid;
109
+ groupingKey = NOTIFICATION_REASON.SUBSCRIBED_POST;
102
110
  }
103
- items.push({
104
- raw: notif,
105
- id,
106
- groupingKey,
107
- actorDid,
108
- });
111
+ items.push(buildNotificationItem(notif, id, groupingKey, actorDid));
109
112
  }
110
- const groupingResult = buildGroups(items, params.limit, now, seenAt, ctx.cfg.notificationsV2Algorithm, feed);
113
+ const groupingStart = performance.now();
114
+ const groupingResult = buildGroups(items.slice(firstNewItem));
115
+ events.notificationGrouping({
116
+ algorithm,
117
+ durationMs: performance.now() - groupingStart,
118
+ });
111
119
  groups = groupingResult.groups;
112
120
  // After fetching a page from the dataplane and attempting to group, 2 situations can happen:
113
121
  // 1. The first unconsumed notification would create an additional group beyond params.limit.
@@ -126,11 +134,14 @@ const skeleton = async (input) => {
126
134
  break;
127
135
  }
128
136
  return {
129
- ...buildSpotlight(items, groups, nextCursor, params.limit, seenAt),
137
+ ...buildSpotlight(items, groups, nextCursor, params.limit, now, seenAt, splitBursts),
130
138
  itemsFetched,
139
+ dataplaneFetches,
140
+ hydrationDurationMs: 0,
131
141
  };
132
142
  };
133
143
  const hydration = async (input) => {
144
+ const hydrationStart = performance.now();
134
145
  const { ctx, params, skeleton } = input;
135
146
  const notifs = skeleton.groups.flatMap((group) => group.items.map((item) => item.raw));
136
147
  // Optimization: instead of fetching known followers for all users in all notifications,
@@ -139,9 +150,9 @@ const hydration = async (input) => {
139
150
  const knownFollowersDids = dedupeStrs(skeleton.groups.flatMap((group) => group.kind === NOTIFICATION_REASON.FOLLOW
140
151
  ? truncateRelatedViewsItems(group.items, ctx.cfg.notificationsV2MaxGroupItemsWithRelatedViews).map((item) => item.actorDid)
141
152
  : []));
142
- return ctx.hydrator.hydrateGroupedNotifications(notifs, params.hydrateCtx, {
143
- knownFollowersDids,
144
- });
153
+ const hydrated = await ctx.hydrator.hydrateGroupedNotifications(notifs, params.hydrateCtx, { knownFollowersDids });
154
+ skeleton.hydrationDurationMs = performance.now() - hydrationStart;
155
+ return hydrated;
145
156
  };
146
157
  const rules = (input) => {
147
158
  const { ctx, params, skeleton, hydration } = input;
@@ -166,7 +177,7 @@ const rules = (input) => {
166
177
  }
167
178
  // After hydration, notificationAvailable checks whether each notification’s required records exist.
168
179
  // If its actor, post, repost, follow, or starter pack is missing or blocked, rules removes that notification from the returned group.
169
- return notificationAvailable(notif, hydration, ctx.views);
180
+ return notificationAvailable(item, hydration, ctx.views);
170
181
  });
171
182
  const newest = items[0];
172
183
  const oldest = items.at(-1);
@@ -189,14 +200,22 @@ const rules = (input) => {
189
200
  return { ...skeleton, groups };
190
201
  };
191
202
  // Checks that the notification’s actor and required records exist and referenced posts aren’t viewer-blocked.
192
- const notificationAvailable = (notif, state, views) => {
203
+ const notificationAvailable = (item, state, views) => {
204
+ const { raw: notif, actorDid } = item;
193
205
  const uri = notif.uri;
194
- const actor = state.actors?.get(uriToDid(uri));
206
+ const actor = state.actors?.get(actorDid);
195
207
  if (!actor)
196
208
  return false;
197
- const postAvailable = (postUri) => !!state.posts?.get(postUri) &&
198
- !!state.actors?.get(uriToDid(postUri)) &&
199
- !views.viewerBlockExists(uriToDid(postUri), state);
209
+ const postAvailable = (postUri) => {
210
+ if (!state.posts?.get(postUri))
211
+ return false;
212
+ // Notifications can refer to a post itself (mentions) or to a like/repost of that post,
213
+ // whose author is not necessarily the post author; matching URIs mean actorDid is the post author,
214
+ // otherwise extract it from postUri.
215
+ const postAuthorDid = postUri === uri ? actorDid : uriToDid(postUri);
216
+ return (!!state.actors?.get(postAuthorDid) &&
217
+ !views.viewerBlockExists(postAuthorDid, state));
218
+ };
200
219
  const starterPackAvailable = (starterPackUri) => !!state.starterPacks?.get(starterPackUri) &&
201
220
  !!state.actors?.get(uriToDid(starterPackUri));
202
221
  switch (notif.reason) {
@@ -348,6 +367,8 @@ const presentation = (input) => {
348
367
  events.groupedNotifications({
349
368
  itemsFetched: skeleton.itemsFetched,
350
369
  itemsReturned: groups.reduce((count, group) => count + group.count, 0),
370
+ dataplaneFetches: skeleton.dataplaneFetches,
371
+ hydrationDurationMs: skeleton.hydrationDurationMs,
351
372
  });
352
373
  return body;
353
374
  };
@@ -1 +1 @@
1
- {"version":3,"file":"getGroupedNotifications.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/notification/getGroupedNotifications.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto'\nimport { dedupeStrs, mapDefined } from '@atproto/common'\nimport {\n type AtUriString,\n type DatetimeString,\n type DidString,\n asDatetimeString,\n} from '@atproto/lex'\nimport { AtUri } from '@atproto/syntax'\nimport type { Server } from '@atproto/xrpc-server'\nimport type { ServerConfig } from '../../../../config.js'\nimport type { AppContext } from '../../../../context.js'\nimport type {\n HydrateCtxWithViewer,\n HydrationState,\n Hydrator,\n} from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type RulesFnInput,\n type SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline.js'\nimport { NotificationFeed } from '../../../../proto/bsky_pb.js'\nimport { events } from '../../../../telemetry/events.js'\nimport { uriToDid } from '../../../../util/uris.js'\nimport type { Views } from '../../../../views/index.js'\nimport { resHeaders } from '../../../util.js'\nimport { NOTIFICATION_REASON } from './constants.js'\nimport {\n type NotificationGroup,\n type NotificationItem,\n type RawNotification,\n buildGroups,\n parseRawNotification,\n} from './grouping/grouping.js'\nimport {\n compareNotificationGroupsNewestFirst,\n isNotificationRead,\n} from './grouping/shared.js'\nimport { buildSpotlight } from './grouping/spotlight.js'\nimport {\n delayCursor,\n shouldFilterForNeedsReview,\n shouldFilterHiddenThreadTag,\n shouldFilterReplyByThreadgate,\n} from './util.js'\n\nexport const getNextRawLimit = (\n itemsFetched: number,\n groupsBuilt: number,\n groupsNeeded: number,\n minRawLimit: number,\n maxRawItems: number,\n): number => {\n // How many raw items we still can fetch until hit the max.\n const remainingItems = maxRawItems - itemsFetched\n if (remainingItems <= 0) return 0\n\n // Defensive fallback to avoid a division by 0 later.\n // This is for the scenario where fetched items but couldn't build any groups with them\n // (let's say all notifications are missing data and are filtered out, shouldn't happen in practice).\n if (groupsBuilt === 0) return Math.min(minRawLimit, remainingItems)\n\n // How many groups still to be built - note that we might still fit items into existing groups.\n const groupsMissing = Math.max(0, groupsNeeded - groupsBuilt)\n\n const averagePerGroup = itemsFetched / groupsBuilt\n\n // Estimate additional raw notifications from the average group size.\n const estimatedRawItems = Math.ceil(averagePerGroup * groupsMissing)\n\n // Keep the estimate above the minimum batch and within the total raw-item budget.\n return Math.min(remainingItems, Math.max(minRawLimit, estimatedRawItems))\n}\n\nexport default function (server: Server, ctx: AppContext) {\n const getGroupedNotifications = createPipeline(\n skeleton,\n hydration,\n rules,\n presentation,\n )\n server.add(app.bsky.notification.getGroupedNotifications, {\n auth: ctx.authVerifier.standard,\n handler: async ({ params, auth, req }) => {\n const viewer = auth.credentials.iss\n const features = ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({ viewer, req }),\n )\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n labelers,\n viewer,\n features,\n })\n const lastSeenRes = await ctx.hydrator.dataplane.getNotificationSeen({\n actorDid: viewer,\n })\n const seenAt = lastSeenRes.timestamp\n ? asDatetimeString(lastSeenRes.timestamp.toJson() as string)\n : undefined\n const body = await getGroupedNotifications(\n { ...params, hydrateCtx, seenAt },\n ctx,\n )\n return {\n encoding: 'application/json',\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n body,\n }\n },\n })\n}\n\nconst skeleton = async (\n input: SkeletonFnInput<Context, Params>,\n): Promise<SkeletonState> => {\n const { ctx, params } = input\n const now = Date.now()\n const feed = normalizeFeed(params.feed)\n const seenAt = params.seenAt ? Date.parse(params.seenAt) : undefined\n const delayedCursor = delayCursor(undefined, ctx.cfg.notificationsDelayMs)\n let cursor = params.cursor\n if (!cursor || Date.parse(cursor) > Date.parse(delayedCursor)) {\n cursor = delayedCursor\n }\n\n const items: NotificationItem[] = []\n let groups: NotificationGroup[] = []\n let nextCursor: string | undefined\n let itemsFetched = 0\n let rawLimit = ctx.cfg.notificationsV2MinRawLimit\n\n for (let read = 0; read < ctx.cfg.notificationsV2MaxReads; read++) {\n const response = await ctx.hydrator.dataplane.getNotificationsV2({\n actorDid: params.hydrateCtx.viewer,\n feed,\n cursor,\n limit: rawLimit,\n })\n itemsFetched += response.notifications.length\n\n for (const notification of response.notifications) {\n const notif = parseRawNotification(notification)\n if (!notif) continue\n const uri = notif.uri\n const actorDid = uriToDid(uri)\n const indexedAt = notif.indexedAt\n // Hashing keeps IDs within the lexicon's length limit for long record URIs.\n const id = createHash('sha256')\n .update(`${indexedAt}\\0${uri}`)\n .digest('base64url')\n\n let groupingKey: string = notif.reasonSubject || uri\n if (notif.reason === NOTIFICATION_REASON.FOLLOW) {\n groupingKey = NOTIFICATION_REASON.FOLLOW\n }\n if (notif.reason === NOTIFICATION_REASON.SUBSCRIBED_POST) {\n groupingKey = actorDid\n }\n\n items.push({\n raw: notif,\n id,\n groupingKey,\n actorDid,\n })\n }\n\n const groupingResult = buildGroups(\n items,\n params.limit,\n now,\n seenAt,\n ctx.cfg.notificationsV2Algorithm,\n feed,\n )\n groups = groupingResult.groups\n\n // After fetching a page from the dataplane and attempting to group, 2 situations can happen:\n // 1. The first unconsumed notification would create an additional group beyond params.limit.\n // result.cursor points before that notification; use it so the next request processes it.\n // 2. Every fetched notification was consumed into the groups.\n // result.cursor is undefined, so use response.cursor to fetch the next dataplane page.\n nextCursor = groupingResult.cursor ?? (response.cursor || undefined)\n\n const groupingFoundUnconsumedNotification =\n groupingResult.cursor !== undefined\n const dataplaneHasMoreNotifications = !!response.cursor\n const shouldContinueBuildingPage =\n !groupingFoundUnconsumedNotification && dataplaneHasMoreNotifications\n if (!shouldContinueBuildingPage) break\n\n cursor = response.cursor\n rawLimit = getNextRawLimit(\n itemsFetched,\n groups.length,\n params.limit,\n ctx.cfg.notificationsV2MinRawLimit,\n ctx.cfg.notificationsV2MaxRawItems,\n )\n if (rawLimit === 0) break\n }\n\n return {\n ...buildSpotlight(items, groups, nextCursor, params.limit, seenAt),\n itemsFetched,\n }\n}\n\nconst hydration = async (\n input: HydrationFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, params, skeleton } = input\n const notifs = skeleton.groups.flatMap((group) =>\n group.items.map((item) => item.raw),\n )\n\n // Optimization: instead of fetching known followers for all users in all notifications,\n // only fetch for the notifications type that want it (follow type), and only for the ones\n // that appear before truncation.\n const knownFollowersDids = dedupeStrs(\n skeleton.groups.flatMap((group) =>\n group.kind === NOTIFICATION_REASON.FOLLOW\n ? truncateRelatedViewsItems(\n group.items,\n ctx.cfg.notificationsV2MaxGroupItemsWithRelatedViews,\n ).map((item) => item.actorDid)\n : [],\n ),\n )\n\n return ctx.hydrator.hydrateGroupedNotifications(notifs, params.hydrateCtx, {\n knownFollowersDids,\n })\n}\n\nconst rules = (\n input: RulesFnInput<Context, Params, SkeletonState>,\n): SkeletonState => {\n const { ctx, params, skeleton, hydration } = input\n const seenAt = params.seenAt ? Date.parse(params.seenAt) : undefined\n const groups = mapDefined(\n skeleton.groups,\n (group): NotificationGroup | undefined => {\n const items = group.items.filter((item) => {\n const notif = item.raw\n const uri = notif.uri\n const did = item.actorDid\n if (\n ctx.views.viewerBlockExists(did, hydration) ||\n ctx.views.viewerMuteExists(did, hydration)\n ) {\n return false\n }\n if (\n shouldFilterReplyByThreadgate(\n notif.reason,\n uri,\n params.hydrateCtx.viewer,\n hydration,\n ctx.views,\n )\n ) {\n return false\n }\n if (\n shouldFilterHiddenThreadTag(\n notif.reason,\n uri,\n did,\n hydration,\n ctx.cfg.threadTagsHide,\n )\n ) {\n return false\n }\n if (\n shouldFilterForNeedsReview(\n notif.reason,\n did,\n uri,\n hydration,\n ctx.views,\n )\n ) {\n return false\n }\n\n // After hydration, notificationAvailable checks whether each notification’s required records exist.\n // If its actor, post, repost, follow, or starter pack is missing or blocked, rules removes that notification from the returned group.\n return notificationAvailable(notif, hydration, ctx.views)\n })\n\n const newest = items[0]\n const oldest = items.at(-1)\n\n // If it has no more elements, drop this group.\n if (!newest || !oldest) return\n\n // Filtering may remove notifications from this group; build a new group with only the remaining items and their updated metadata.\n return {\n ...group,\n id: newest.id,\n items,\n actorDids: items.map((item) => item.actorDid),\n itemCount: items.length,\n indexedAt: newest.raw.indexedAt,\n firstIndexedAt: oldest.raw.indexedAt,\n isRead: isNotificationRead(newest.raw.indexedAt, seenAt),\n }\n },\n )\n\n groups.sort(compareNotificationGroupsNewestFirst)\n\n return { ...skeleton, groups }\n}\n\n// Checks that the notification’s actor and required records exist and referenced posts aren’t viewer-blocked.\nconst notificationAvailable = (\n notif: RawNotification,\n state: HydrationState,\n views: Views,\n): boolean => {\n const uri = notif.uri\n const actor = state.actors?.get(uriToDid(uri))\n if (!actor) return false\n\n const postAvailable = (postUri: AtUriString) =>\n !!state.posts?.get(postUri) &&\n !!state.actors?.get(uriToDid(postUri)) &&\n !views.viewerBlockExists(uriToDid(postUri), state)\n\n const starterPackAvailable = (starterPackUri: AtUriString) =>\n !!state.starterPacks?.get(starterPackUri) &&\n !!state.actors?.get(uriToDid(starterPackUri))\n\n switch (notif.reason) {\n case NOTIFICATION_REASON.LIKE: {\n const subjectUri = notif.reasonSubject\n if (!state.likes?.get(uri)) return false\n if (new AtUri(subjectUri).collection === app.bsky.feed.generator.$type) {\n return (\n !!state.feedgens?.get(subjectUri) &&\n !!state.actors?.get(uriToDid(subjectUri))\n )\n }\n return postAvailable(subjectUri)\n }\n case NOTIFICATION_REASON.REPOST:\n return !!state.reposts?.get(uri) && postAvailable(notif.reasonSubject)\n case NOTIFICATION_REASON.LIKE_VIA_REPOST:\n case NOTIFICATION_REASON.REPOST_VIA_REPOST: {\n const recordInfo =\n notif.reason === NOTIFICATION_REASON.LIKE_VIA_REPOST\n ? state.likes?.get(uri)\n : state.reposts?.get(uri)\n const postUri = state.reposts?.get(notif.reasonSubject)?.record.subject\n .uri\n return !!recordInfo && !!postUri && postAvailable(postUri)\n }\n case NOTIFICATION_REASON.FOLLOW:\n case NOTIFICATION_REASON.FOLLOW_BACK:\n return !!state.follows?.get(uri)\n case NOTIFICATION_REASON.REPLY:\n return (\n postAvailable(uri) && !!state.posts?.get(uri)?.record.reply?.parent.uri\n )\n case NOTIFICATION_REASON.QUOTE:\n case NOTIFICATION_REASON.MENTION:\n case NOTIFICATION_REASON.SUBSCRIBED_POST:\n return postAvailable(uri)\n case NOTIFICATION_REASON.VERIFIED:\n case NOTIFICATION_REASON.UNVERIFIED:\n // Both notifications survive deletion of the verification record.\n return true\n case NOTIFICATION_REASON.STARTERPACK_JOINED:\n return (\n !!actor.profile &&\n !!actor.profileCid &&\n starterPackAvailable(notif.reasonSubject)\n )\n case NOTIFICATION_REASON.CONTACT_MATCH:\n return !!actor.profile && !!actor.profileCid\n default:\n return false\n }\n}\n\nconst presentation = (\n input: PresentationFnInput<Context, Params, SkeletonState>,\n): app.bsky.notification.getGroupedNotifications.$OutputBody => {\n const { ctx, params, skeleton, hydration } = input\n const defs = app.bsky.notification.getGroupedNotifications\n const groups = mapDefined(skeleton.groups, (group) =>\n ctx.views.notificationGroup(group, hydration),\n )\n\n const maxGroupItems = ctx.cfg.notificationsV2MaxGroupItemsWithRelatedViews\n\n // Build related profiles, records.\n const profileDids = new Set<DidString>()\n const recordUris = new Set<AtUriString>()\n for (const { kind } of groups) {\n if (\n defs.likeGroup.$isTypeOf(kind) ||\n defs.repostGroup.$isTypeOf(kind) ||\n defs.likeViaRepostGroup.$isTypeOf(kind) ||\n defs.repostViaRepostGroup.$isTypeOf(kind)\n ) {\n recordUris.add(kind.post)\n for (const item of truncateRelatedViewsItems(kind.items, maxGroupItems)) {\n profileDids.add(item.actor)\n }\n } else if (\n defs.multiPostLikeGroup.$isTypeOf(kind) ||\n defs.multiPostRepostGroup.$isTypeOf(kind) ||\n defs.multiPostLikeViaRepostGroup.$isTypeOf(kind) ||\n defs.multiPostRepostViaRepostGroup.$isTypeOf(kind)\n ) {\n profileDids.add(kind.actor)\n for (const item of truncateRelatedViewsItems(kind.items, maxGroupItems)) {\n recordUris.add(item.post)\n }\n } else if (defs.generatorLikeGroup.$isTypeOf(kind)) {\n recordUris.add(kind.generator)\n for (const item of truncateRelatedViewsItems(kind.items, maxGroupItems)) {\n profileDids.add(item.actor)\n }\n } else if (defs.followGroup.$isTypeOf(kind)) {\n for (const item of truncateRelatedViewsItems(kind.items, maxGroupItems)) {\n profileDids.add(item.actor)\n if (item.starterPack) recordUris.add(item.starterPack)\n }\n } else if (defs.subscribedPostGroup.$isTypeOf(kind)) {\n for (const item of truncateRelatedViewsItems(kind.items, maxGroupItems)) {\n profileDids.add(item.actor)\n recordUris.add(item.post)\n if (item.parent) recordUris.add(item.parent)\n }\n } else if (\n defs.replyNotification.$isTypeOf(kind) ||\n defs.quoteNotification.$isTypeOf(kind) ||\n defs.mentionNotification.$isTypeOf(kind)\n ) {\n recordUris.add(kind.post)\n if (kind.parent) recordUris.add(kind.parent)\n } else if (\n defs.followBackNotification.$isTypeOf(kind) ||\n defs.starterPackJoinedNotification.$isTypeOf(kind)\n ) {\n profileDids.add(kind.actor)\n if (kind.starterPack) recordUris.add(kind.starterPack)\n } else if (\n defs.verifiedNotification.$isTypeOf(kind) ||\n defs.unverifiedNotification.$isTypeOf(kind) ||\n defs.contactMatchNotification.$isTypeOf(kind)\n ) {\n profileDids.add(kind.actor)\n }\n }\n\n const body = {\n groups,\n relatedViews: [\n ...mapDefined([...profileDids], (did) => {\n const view = ctx.views.profileBasic(did, hydration)\n if (!view) return\n return app.bsky.actor.defs.profileViewBasic.$build(view)\n }),\n ...mapDefined([...recordUris], (uri) => {\n const collection = new AtUri(uri).collection\n if (collection === app.bsky.feed.post.$type) {\n const view = ctx.views.maybePost(uri, hydration)\n if (!view) return\n return view\n } else if (collection === app.bsky.graph.starterpack.$type) {\n const view = ctx.views.starterPackBasic(uri, hydration)\n if (!view) return\n return app.bsky.graph.defs.starterPackViewBasic.$build(view)\n } else if (collection === app.bsky.feed.generator.$type) {\n const view = ctx.views.feedGenerator(uri, hydration)\n if (!view) return\n return app.bsky.feed.defs.generatorView.$build(view)\n }\n }),\n ],\n cursor: skeleton.cursor,\n seenAt: params.seenAt,\n }\n\n events.groupedNotifications({\n itemsFetched: skeleton.itemsFetched,\n itemsReturned: groups.reduce((count, group) => count + group.count, 0),\n })\n\n return body\n}\n\nconst truncateRelatedViewsItems = <T extends unknown[]>(\n items: T,\n maxItems: number,\n): T[number][] => items.slice(0, maxItems)\n\nconst normalizeFeed = (feed: string): NotificationFeed => {\n switch (feed) {\n case 'people-i-follow':\n return NotificationFeed.PEOPLE_I_FOLLOW\n case 'conversations':\n return NotificationFeed.CONVERSATIONS\n case 'followers':\n return NotificationFeed.FOLLOWERS\n case 'activity':\n return NotificationFeed.ACTIVITY\n default:\n return NotificationFeed.ALL\n }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n cfg: ServerConfig\n}\n\ntype Params = app.bsky.notification.getGroupedNotifications.$Params & {\n hydrateCtx: HydrateCtxWithViewer\n seenAt?: DatetimeString\n}\n\ntype SkeletonState = {\n groups: NotificationGroup[]\n cursor?: string\n itemsFetched: number\n}\n"]}
1
+ {"version":3,"file":"getGroupedNotifications.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/notification/getGroupedNotifications.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto'\nimport { performance } from 'node:perf_hooks'\nimport { dedupeStrs, mapDefined } from '@atproto/common'\nimport {\n type AtUriString,\n type DatetimeString,\n type DidString,\n asDatetimeString,\n} from '@atproto/lex'\nimport { AtUri } from '@atproto/syntax'\nimport type { Server } from '@atproto/xrpc-server'\nimport type { ServerConfig } from '../../../../config.js'\nimport type { AppContext } from '../../../../context.js'\nimport type {\n HydrateCtxWithViewer,\n HydrationState,\n Hydrator,\n} from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type RulesFnInput,\n type SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline.js'\nimport { NotificationFeed } from '../../../../proto/bsky_pb.js'\nimport { events } from '../../../../telemetry/events.js'\nimport { uriToDid } from '../../../../util/uris.js'\nimport type { Views } from '../../../../views/index.js'\nimport { resHeaders } from '../../../util.js'\nimport { NOTIFICATION_REASON } from './constants.js'\nimport {\n type NotificationGroup,\n type NotificationItem,\n buildNotificationItem,\n getGroupingAlgorithm,\n parseRawNotification,\n} from './grouping/grouping.js'\nimport {\n compareNotificationGroupsNewestFirst,\n isNotificationRead,\n} from './grouping/shared.js'\nimport { buildSpotlight } from './grouping/spotlight.js'\nimport {\n delayCursor,\n shouldFilterForNeedsReview,\n shouldFilterHiddenThreadTag,\n shouldFilterReplyByThreadgate,\n} from './util.js'\n\nexport const getNextRawLimit = (\n itemsFetched: number,\n groupsBuilt: number,\n groupsNeeded: number,\n minRawLimit: number,\n maxRawItems: number,\n): number => {\n // How many raw items we still can fetch until hit the max.\n const remainingItems = maxRawItems - itemsFetched\n if (remainingItems <= 0) return 0\n\n // Defensive fallback to avoid a division by 0 later.\n // This is for the scenario where fetched items but couldn't build any groups with them\n // (let's say all notifications are missing data and are filtered out, shouldn't happen in practice).\n if (groupsBuilt === 0) return Math.min(minRawLimit, remainingItems)\n\n // How many groups still to be built - note that we might still fit items into existing groups.\n const groupsMissing = Math.max(0, groupsNeeded - groupsBuilt)\n\n const averagePerGroup = itemsFetched / groupsBuilt\n\n // Estimate additional raw notifications from the average group size.\n const estimatedRawItems = Math.ceil(averagePerGroup * groupsMissing)\n\n // Keep the estimate above the minimum batch and within the total raw-item budget.\n return Math.min(remainingItems, Math.max(minRawLimit, estimatedRawItems))\n}\n\nexport default function (server: Server, ctx: AppContext) {\n const getGroupedNotifications = createPipeline(\n skeleton,\n hydration,\n rules,\n presentation,\n )\n server.add(app.bsky.notification.getGroupedNotifications, {\n auth: ctx.authVerifier.standard,\n handler: async ({ params, auth, req }) => {\n const viewer = auth.credentials.iss\n const features = ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({ viewer, req }),\n )\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n xrpcEndpoint: app.bsky.notification.getGroupedNotifications.$lxm,\n labelers,\n viewer,\n features,\n })\n const lastSeenRes = await ctx.hydrator.dataplane.getNotificationSeen({\n actorDid: viewer,\n })\n const seenAt = lastSeenRes.timestamp\n ? asDatetimeString(lastSeenRes.timestamp.toJson() as string)\n : undefined\n const body = await getGroupedNotifications(\n { ...params, hydrateCtx, seenAt },\n ctx,\n )\n return {\n encoding: 'application/json',\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n body,\n }\n },\n })\n}\n\nconst skeleton = async (\n input: SkeletonFnInput<Context, Params>,\n): Promise<SkeletonState> => {\n const { ctx, params } = input\n const now = Date.now()\n const feed = normalizeFeed(params.feed)\n const seenAt = params.seenAt ? Date.parse(params.seenAt) : undefined\n const delayedCursor = delayCursor(undefined, ctx.cfg.notificationsDelayMs)\n let cursor = params.cursor\n if (!cursor || Date.parse(cursor) > Date.parse(delayedCursor)) {\n cursor = delayedCursor\n }\n\n const items: NotificationItem[] = []\n let groups: NotificationGroup[] = []\n let nextCursor: string | undefined\n let itemsFetched = 0\n let dataplaneFetches = 0\n let rawLimit = ctx.cfg.notificationsV2MinRawLimit\n const algorithm = ctx.cfg.notificationsV2Algorithm\n const { createGroupBuilder, splitBursts } = getGroupingAlgorithm(algorithm)\n const buildGroups = createGroupBuilder(params.limit, now, seenAt, feed)\n\n for (\n let fetches = 0;\n fetches < ctx.cfg.notificationsV2MaxFetches;\n fetches++\n ) {\n const response = await ctx.hydrator.dataplane.getNotificationsV2({\n actorDid: params.hydrateCtx.viewer,\n feed,\n cursor,\n limit: rawLimit,\n })\n dataplaneFetches++\n itemsFetched += response.notifications.length\n\n const firstNewItem = items.length\n for (const notification of response.notifications) {\n const notif = parseRawNotification(notification)\n if (!notif) continue\n const uri = notif.uri\n const actorDid = uriToDid(uri)\n const indexedAt = notif.indexedAt\n // Hashing keeps IDs within the lexicon's length limit for long record URIs.\n const id = createHash('sha256')\n .update(`${indexedAt}\\0${uri}`)\n .digest('base64url')\n\n let groupingKey: string = notif.reasonSubject || uri\n if (notif.reason === NOTIFICATION_REASON.FOLLOW) {\n groupingKey = NOTIFICATION_REASON.FOLLOW\n }\n if (notif.reason === NOTIFICATION_REASON.SUBSCRIBED_POST) {\n groupingKey = NOTIFICATION_REASON.SUBSCRIBED_POST\n }\n\n items.push(buildNotificationItem(notif, id, groupingKey, actorDid))\n }\n\n const groupingStart = performance.now()\n const groupingResult = buildGroups(items.slice(firstNewItem))\n events.notificationGrouping({\n algorithm,\n durationMs: performance.now() - groupingStart,\n })\n groups = groupingResult.groups\n\n // After fetching a page from the dataplane and attempting to group, 2 situations can happen:\n // 1. The first unconsumed notification would create an additional group beyond params.limit.\n // result.cursor points before that notification; use it so the next request processes it.\n // 2. Every fetched notification was consumed into the groups.\n // result.cursor is undefined, so use response.cursor to fetch the next dataplane page.\n nextCursor = groupingResult.cursor ?? (response.cursor || undefined)\n\n const groupingFoundUnconsumedNotification =\n groupingResult.cursor !== undefined\n const dataplaneHasMoreNotifications = !!response.cursor\n const shouldContinueBuildingPage =\n !groupingFoundUnconsumedNotification && dataplaneHasMoreNotifications\n if (!shouldContinueBuildingPage) break\n\n cursor = response.cursor\n rawLimit = getNextRawLimit(\n itemsFetched,\n groups.length,\n params.limit,\n ctx.cfg.notificationsV2MinRawLimit,\n ctx.cfg.notificationsV2MaxRawItems,\n )\n if (rawLimit === 0) break\n }\n\n return {\n ...buildSpotlight(\n items,\n groups,\n nextCursor,\n params.limit,\n now,\n seenAt,\n splitBursts,\n ),\n itemsFetched,\n dataplaneFetches,\n hydrationDurationMs: 0,\n }\n}\n\nconst hydration = async (\n input: HydrationFnInput<Context, Params, SkeletonState>,\n) => {\n const hydrationStart = performance.now()\n const { ctx, params, skeleton } = input\n const notifs = skeleton.groups.flatMap((group) =>\n group.items.map((item) => item.raw),\n )\n\n // Optimization: instead of fetching known followers for all users in all notifications,\n // only fetch for the notifications type that want it (follow type), and only for the ones\n // that appear before truncation.\n const knownFollowersDids = dedupeStrs(\n skeleton.groups.flatMap((group) =>\n group.kind === NOTIFICATION_REASON.FOLLOW\n ? truncateRelatedViewsItems(\n group.items,\n ctx.cfg.notificationsV2MaxGroupItemsWithRelatedViews,\n ).map((item) => item.actorDid)\n : [],\n ),\n )\n\n const hydrated = await ctx.hydrator.hydrateGroupedNotifications(\n notifs,\n params.hydrateCtx,\n { knownFollowersDids },\n )\n skeleton.hydrationDurationMs = performance.now() - hydrationStart\n return hydrated\n}\n\nconst rules = (\n input: RulesFnInput<Context, Params, SkeletonState>,\n): SkeletonState => {\n const { ctx, params, skeleton, hydration } = input\n const seenAt = params.seenAt ? Date.parse(params.seenAt) : undefined\n const groups = mapDefined(\n skeleton.groups,\n (group): NotificationGroup | undefined => {\n const items = group.items.filter((item) => {\n const notif = item.raw\n const uri = notif.uri\n const did = item.actorDid\n if (\n ctx.views.viewerBlockExists(did, hydration) ||\n ctx.views.viewerMuteExists(did, hydration)\n ) {\n return false\n }\n if (\n shouldFilterReplyByThreadgate(\n notif.reason,\n uri,\n params.hydrateCtx.viewer,\n hydration,\n ctx.views,\n )\n ) {\n return false\n }\n if (\n shouldFilterHiddenThreadTag(\n notif.reason,\n uri,\n did,\n hydration,\n ctx.cfg.threadTagsHide,\n )\n ) {\n return false\n }\n if (\n shouldFilterForNeedsReview(\n notif.reason,\n did,\n uri,\n hydration,\n ctx.views,\n )\n ) {\n return false\n }\n\n // After hydration, notificationAvailable checks whether each notification’s required records exist.\n // If its actor, post, repost, follow, or starter pack is missing or blocked, rules removes that notification from the returned group.\n return notificationAvailable(item, hydration, ctx.views)\n })\n\n const newest = items[0]\n const oldest = items.at(-1)\n\n // If it has no more elements, drop this group.\n if (!newest || !oldest) return\n\n // Filtering may remove notifications from this group; build a new group with only the remaining items and their updated metadata.\n return {\n ...group,\n id: newest.id,\n items,\n actorDids: items.map((item) => item.actorDid),\n itemCount: items.length,\n indexedAt: newest.raw.indexedAt,\n firstIndexedAt: oldest.raw.indexedAt,\n isRead: isNotificationRead(newest.raw.indexedAt, seenAt),\n }\n },\n )\n\n groups.sort(compareNotificationGroupsNewestFirst)\n\n return { ...skeleton, groups }\n}\n\n// Checks that the notification’s actor and required records exist and referenced posts aren’t viewer-blocked.\nconst notificationAvailable = (\n item: NotificationItem,\n state: HydrationState,\n views: Views,\n): boolean => {\n const { raw: notif, actorDid } = item\n const uri = notif.uri\n const actor = state.actors?.get(actorDid)\n if (!actor) return false\n\n const postAvailable = (postUri: AtUriString) => {\n if (!state.posts?.get(postUri)) return false\n // Notifications can refer to a post itself (mentions) or to a like/repost of that post,\n // whose author is not necessarily the post author; matching URIs mean actorDid is the post author,\n // otherwise extract it from postUri.\n const postAuthorDid = postUri === uri ? actorDid : uriToDid(postUri)\n return (\n !!state.actors?.get(postAuthorDid) &&\n !views.viewerBlockExists(postAuthorDid, state)\n )\n }\n\n const starterPackAvailable = (starterPackUri: AtUriString) =>\n !!state.starterPacks?.get(starterPackUri) &&\n !!state.actors?.get(uriToDid(starterPackUri))\n\n switch (notif.reason) {\n case NOTIFICATION_REASON.LIKE: {\n const subjectUri = notif.reasonSubject\n if (!state.likes?.get(uri)) return false\n if (new AtUri(subjectUri).collection === app.bsky.feed.generator.$type) {\n return (\n !!state.feedgens?.get(subjectUri) &&\n !!state.actors?.get(uriToDid(subjectUri))\n )\n }\n return postAvailable(subjectUri)\n }\n case NOTIFICATION_REASON.REPOST:\n return !!state.reposts?.get(uri) && postAvailable(notif.reasonSubject)\n case NOTIFICATION_REASON.LIKE_VIA_REPOST:\n case NOTIFICATION_REASON.REPOST_VIA_REPOST: {\n const recordInfo =\n notif.reason === NOTIFICATION_REASON.LIKE_VIA_REPOST\n ? state.likes?.get(uri)\n : state.reposts?.get(uri)\n const postUri = state.reposts?.get(notif.reasonSubject)?.record.subject\n .uri\n return !!recordInfo && !!postUri && postAvailable(postUri)\n }\n case NOTIFICATION_REASON.FOLLOW:\n case NOTIFICATION_REASON.FOLLOW_BACK:\n return !!state.follows?.get(uri)\n case NOTIFICATION_REASON.REPLY:\n return (\n postAvailable(uri) && !!state.posts?.get(uri)?.record.reply?.parent.uri\n )\n case NOTIFICATION_REASON.QUOTE:\n case NOTIFICATION_REASON.MENTION:\n case NOTIFICATION_REASON.SUBSCRIBED_POST:\n return postAvailable(uri)\n case NOTIFICATION_REASON.VERIFIED:\n case NOTIFICATION_REASON.UNVERIFIED:\n // Both notifications survive deletion of the verification record.\n return true\n case NOTIFICATION_REASON.STARTERPACK_JOINED:\n return (\n !!actor.profile &&\n !!actor.profileCid &&\n starterPackAvailable(notif.reasonSubject)\n )\n case NOTIFICATION_REASON.CONTACT_MATCH:\n return !!actor.profile && !!actor.profileCid\n default:\n return false\n }\n}\n\nconst presentation = (\n input: PresentationFnInput<Context, Params, SkeletonState>,\n): app.bsky.notification.getGroupedNotifications.$OutputBody => {\n const { ctx, params, skeleton, hydration } = input\n const defs = app.bsky.notification.getGroupedNotifications\n const groups = mapDefined(skeleton.groups, (group) =>\n ctx.views.notificationGroup(group, hydration),\n )\n\n const maxGroupItems = ctx.cfg.notificationsV2MaxGroupItemsWithRelatedViews\n\n // Build related profiles, records.\n const profileDids = new Set<DidString>()\n const recordUris = new Set<AtUriString>()\n for (const { kind } of groups) {\n if (\n defs.likeGroup.$isTypeOf(kind) ||\n defs.repostGroup.$isTypeOf(kind) ||\n defs.likeViaRepostGroup.$isTypeOf(kind) ||\n defs.repostViaRepostGroup.$isTypeOf(kind)\n ) {\n recordUris.add(kind.post)\n for (const item of truncateRelatedViewsItems(kind.items, maxGroupItems)) {\n profileDids.add(item.actor)\n }\n } else if (\n defs.multiPostLikeGroup.$isTypeOf(kind) ||\n defs.multiPostRepostGroup.$isTypeOf(kind) ||\n defs.multiPostLikeViaRepostGroup.$isTypeOf(kind) ||\n defs.multiPostRepostViaRepostGroup.$isTypeOf(kind)\n ) {\n profileDids.add(kind.actor)\n for (const item of truncateRelatedViewsItems(kind.items, maxGroupItems)) {\n recordUris.add(item.post)\n }\n } else if (defs.generatorLikeGroup.$isTypeOf(kind)) {\n recordUris.add(kind.generator)\n for (const item of truncateRelatedViewsItems(kind.items, maxGroupItems)) {\n profileDids.add(item.actor)\n }\n } else if (defs.followGroup.$isTypeOf(kind)) {\n for (const item of truncateRelatedViewsItems(kind.items, maxGroupItems)) {\n profileDids.add(item.actor)\n if (item.starterPack) recordUris.add(item.starterPack)\n }\n } else if (defs.subscribedPostGroup.$isTypeOf(kind)) {\n for (const item of truncateRelatedViewsItems(kind.items, maxGroupItems)) {\n profileDids.add(item.actor)\n recordUris.add(item.post)\n if (item.parent) recordUris.add(item.parent)\n }\n } else if (\n defs.replyNotification.$isTypeOf(kind) ||\n defs.quoteNotification.$isTypeOf(kind) ||\n defs.mentionNotification.$isTypeOf(kind)\n ) {\n recordUris.add(kind.post)\n if (kind.parent) recordUris.add(kind.parent)\n } else if (\n defs.followBackNotification.$isTypeOf(kind) ||\n defs.starterPackJoinedNotification.$isTypeOf(kind)\n ) {\n profileDids.add(kind.actor)\n if (kind.starterPack) recordUris.add(kind.starterPack)\n } else if (\n defs.verifiedNotification.$isTypeOf(kind) ||\n defs.unverifiedNotification.$isTypeOf(kind) ||\n defs.contactMatchNotification.$isTypeOf(kind)\n ) {\n profileDids.add(kind.actor)\n }\n }\n\n const body = {\n groups,\n relatedViews: [\n ...mapDefined([...profileDids], (did) => {\n const view = ctx.views.profileBasic(did, hydration)\n if (!view) return\n return app.bsky.actor.defs.profileViewBasic.$build(view)\n }),\n ...mapDefined([...recordUris], (uri) => {\n const collection = new AtUri(uri).collection\n if (collection === app.bsky.feed.post.$type) {\n const view = ctx.views.maybePost(uri, hydration)\n if (!view) return\n return view\n } else if (collection === app.bsky.graph.starterpack.$type) {\n const view = ctx.views.starterPackBasic(uri, hydration)\n if (!view) return\n return app.bsky.graph.defs.starterPackViewBasic.$build(view)\n } else if (collection === app.bsky.feed.generator.$type) {\n const view = ctx.views.feedGenerator(uri, hydration)\n if (!view) return\n return app.bsky.feed.defs.generatorView.$build(view)\n }\n }),\n ],\n cursor: skeleton.cursor,\n seenAt: params.seenAt,\n }\n\n events.groupedNotifications({\n itemsFetched: skeleton.itemsFetched,\n itemsReturned: groups.reduce((count, group) => count + group.count, 0),\n dataplaneFetches: skeleton.dataplaneFetches,\n hydrationDurationMs: skeleton.hydrationDurationMs,\n })\n\n return body\n}\n\nconst truncateRelatedViewsItems = <T extends unknown[]>(\n items: T,\n maxItems: number,\n): T[number][] => items.slice(0, maxItems)\n\nconst normalizeFeed = (feed: string): NotificationFeed => {\n switch (feed) {\n case 'people-i-follow':\n return NotificationFeed.PEOPLE_I_FOLLOW\n case 'conversations':\n return NotificationFeed.CONVERSATIONS\n case 'followers':\n return NotificationFeed.FOLLOWERS\n case 'activity':\n return NotificationFeed.ACTIVITY\n default:\n return NotificationFeed.ALL\n }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n cfg: ServerConfig\n}\n\ntype Params = app.bsky.notification.getGroupedNotifications.$Params & {\n hydrateCtx: HydrateCtxWithViewer\n seenAt?: DatetimeString\n}\n\ntype SkeletonState = {\n groups: NotificationGroup[]\n cursor?: string\n itemsFetched: number\n dataplaneFetches: number\n hydrationDurationMs: number\n}\n"]}