@atproto/bsky 0.0.242 → 0.0.244

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 (344) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/api/app/bsky/actor/searchActors.d.ts.map +1 -1
  3. package/dist/api/app/bsky/actor/searchActors.js +7 -3
  4. package/dist/api/app/bsky/actor/searchActors.js.map +1 -1
  5. package/dist/api/app/bsky/actor/searchActorsTypeahead.d.ts.map +1 -1
  6. package/dist/api/app/bsky/actor/searchActorsTypeahead.js +12 -6
  7. package/dist/api/app/bsky/actor/searchActorsTypeahead.js.map +1 -1
  8. package/dist/api/app/bsky/feed/searchPosts.d.ts.map +1 -1
  9. package/dist/api/app/bsky/feed/searchPosts.js +8 -3
  10. package/dist/api/app/bsky/feed/searchPosts.js.map +1 -1
  11. package/dist/api/app/bsky/graph/searchStarterPacks.d.ts.map +1 -1
  12. package/dist/api/app/bsky/graph/searchStarterPacks.js +7 -3
  13. package/dist/api/app/bsky/graph/searchStarterPacks.js.map +1 -1
  14. package/dist/api/app/bsky/notification/putPreferencesV2.js +4 -1
  15. package/dist/api/app/bsky/notification/putPreferencesV2.js.map +1 -1
  16. package/dist/api/app/bsky/notification/util.d.ts +1 -0
  17. package/dist/api/app/bsky/notification/util.d.ts.map +1 -1
  18. package/dist/api/app/bsky/notification/util.js +7 -7
  19. package/dist/api/app/bsky/notification/util.js.map +1 -1
  20. package/dist/api/app/bsky/unspecced/getPopularFeedGenerators.d.ts.map +1 -1
  21. package/dist/api/app/bsky/unspecced/getPopularFeedGenerators.js +3 -2
  22. package/dist/api/app/bsky/unspecced/getPopularFeedGenerators.js.map +1 -1
  23. package/dist/api/blob-dispatcher.d.ts.map +1 -1
  24. package/dist/api/blob-dispatcher.js +9 -8
  25. package/dist/api/blob-dispatcher.js.map +1 -1
  26. package/dist/api/blob-resolver.d.ts +1 -1
  27. package/dist/api/blob-resolver.d.ts.map +1 -1
  28. package/dist/api/blob-resolver.js +0 -1
  29. package/dist/api/blob-resolver.js.map +1 -1
  30. package/dist/api/util.d.ts +5 -0
  31. package/dist/api/util.d.ts.map +1 -1
  32. package/dist/api/util.js +11 -0
  33. package/dist/api/util.js.map +1 -1
  34. package/dist/config.d.ts +2 -0
  35. package/dist/config.d.ts.map +1 -1
  36. package/dist/config.js +5 -0
  37. package/dist/config.js.map +1 -1
  38. package/dist/data-plane/bsync/index.d.ts +2 -0
  39. package/dist/data-plane/bsync/index.d.ts.map +1 -1
  40. package/dist/data-plane/bsync/index.js +7 -10
  41. package/dist/data-plane/bsync/index.js.map +1 -1
  42. package/dist/data-plane/server/background.d.ts +12 -8
  43. package/dist/data-plane/server/background.d.ts.map +1 -1
  44. package/dist/data-plane/server/background.js +32 -14
  45. package/dist/data-plane/server/background.js.map +1 -1
  46. package/dist/data-plane/server/db/db.d.ts +4 -5
  47. package/dist/data-plane/server/db/db.d.ts.map +1 -1
  48. package/dist/data-plane/server/db/db.js +2 -1
  49. package/dist/data-plane/server/db/db.js.map +1 -1
  50. package/dist/data-plane/server/db/migrations/20230627T212437895Z-optional-handle.d.ts.map +1 -1
  51. package/dist/data-plane/server/db/migrations/20230627T212437895Z-optional-handle.js +2 -4
  52. package/dist/data-plane/server/db/migrations/20230627T212437895Z-optional-handle.js.map +1 -1
  53. package/dist/data-plane/server/db/migrations/provider.d.ts +2 -1
  54. package/dist/data-plane/server/db/migrations/provider.d.ts.map +1 -1
  55. package/dist/data-plane/server/db/migrations/provider.js.map +1 -1
  56. package/dist/data-plane/server/db/pagination.d.ts +3 -2
  57. package/dist/data-plane/server/db/pagination.d.ts.map +1 -1
  58. package/dist/data-plane/server/db/pagination.js +8 -8
  59. package/dist/data-plane/server/db/pagination.js.map +1 -1
  60. package/dist/data-plane/server/db/util.d.ts +5 -5
  61. package/dist/data-plane/server/db/util.d.ts.map +1 -1
  62. package/dist/data-plane/server/db/util.js.map +1 -1
  63. package/dist/data-plane/server/index.d.ts +2 -0
  64. package/dist/data-plane/server/index.d.ts.map +1 -1
  65. package/dist/data-plane/server/index.js +7 -10
  66. package/dist/data-plane/server/index.js.map +1 -1
  67. package/dist/data-plane/server/indexing/index.d.ts +2 -2
  68. package/dist/data-plane/server/indexing/index.d.ts.map +1 -1
  69. package/dist/data-plane/server/indexing/index.js.map +1 -1
  70. package/dist/data-plane/server/indexing/plugins/block.d.ts +9 -4
  71. package/dist/data-plane/server/indexing/plugins/block.d.ts.map +1 -1
  72. package/dist/data-plane/server/indexing/plugins/block.js.map +1 -1
  73. package/dist/data-plane/server/indexing/plugins/chat-declaration.d.ts +1 -1
  74. package/dist/data-plane/server/indexing/plugins/chat-declaration.d.ts.map +1 -1
  75. package/dist/data-plane/server/indexing/plugins/chat-declaration.js.map +1 -1
  76. package/dist/data-plane/server/indexing/plugins/feed-generator.d.ts +13 -4
  77. package/dist/data-plane/server/indexing/plugins/feed-generator.d.ts.map +1 -1
  78. package/dist/data-plane/server/indexing/plugins/feed-generator.js.map +1 -1
  79. package/dist/data-plane/server/indexing/plugins/follow.d.ts +9 -4
  80. package/dist/data-plane/server/indexing/plugins/follow.d.ts.map +1 -1
  81. package/dist/data-plane/server/indexing/plugins/follow.js.map +1 -1
  82. package/dist/data-plane/server/indexing/plugins/germ-declaration.d.ts +1 -1
  83. package/dist/data-plane/server/indexing/plugins/germ-declaration.d.ts.map +1 -1
  84. package/dist/data-plane/server/indexing/plugins/germ-declaration.js.map +1 -1
  85. package/dist/data-plane/server/indexing/plugins/labeler.d.ts +8 -4
  86. package/dist/data-plane/server/indexing/plugins/labeler.d.ts.map +1 -1
  87. package/dist/data-plane/server/indexing/plugins/labeler.js.map +1 -1
  88. package/dist/data-plane/server/indexing/plugins/like.d.ts +12 -4
  89. package/dist/data-plane/server/indexing/plugins/like.d.ts.map +1 -1
  90. package/dist/data-plane/server/indexing/plugins/like.js.map +1 -1
  91. package/dist/data-plane/server/indexing/plugins/list-block.d.ts +9 -4
  92. package/dist/data-plane/server/indexing/plugins/list-block.d.ts.map +1 -1
  93. package/dist/data-plane/server/indexing/plugins/list-block.js.map +1 -1
  94. package/dist/data-plane/server/indexing/plugins/list-item.d.ts +10 -4
  95. package/dist/data-plane/server/indexing/plugins/list-item.d.ts.map +1 -1
  96. package/dist/data-plane/server/indexing/plugins/list-item.js.map +1 -1
  97. package/dist/data-plane/server/indexing/plugins/list.d.ts +13 -4
  98. package/dist/data-plane/server/indexing/plugins/list.d.ts.map +1 -1
  99. package/dist/data-plane/server/indexing/plugins/list.js.map +1 -1
  100. package/dist/data-plane/server/indexing/plugins/notif-declaration.d.ts +1 -1
  101. package/dist/data-plane/server/indexing/plugins/notif-declaration.d.ts.map +1 -1
  102. package/dist/data-plane/server/indexing/plugins/notif-declaration.js.map +1 -1
  103. package/dist/data-plane/server/indexing/plugins/post-gate.d.ts +1 -1
  104. package/dist/data-plane/server/indexing/plugins/post-gate.d.ts.map +1 -1
  105. package/dist/data-plane/server/indexing/plugins/post-gate.js.map +1 -1
  106. package/dist/data-plane/server/indexing/plugins/post.d.ts +1 -1
  107. package/dist/data-plane/server/indexing/plugins/post.d.ts.map +1 -1
  108. package/dist/data-plane/server/indexing/plugins/post.js +4 -3
  109. package/dist/data-plane/server/indexing/plugins/post.js.map +1 -1
  110. package/dist/data-plane/server/indexing/plugins/profile.d.ts +1 -1
  111. package/dist/data-plane/server/indexing/plugins/profile.d.ts.map +1 -1
  112. package/dist/data-plane/server/indexing/plugins/profile.js.map +1 -1
  113. package/dist/data-plane/server/indexing/plugins/repost.d.ts +12 -4
  114. package/dist/data-plane/server/indexing/plugins/repost.d.ts.map +1 -1
  115. package/dist/data-plane/server/indexing/plugins/repost.js.map +1 -1
  116. package/dist/data-plane/server/indexing/plugins/starter-pack.d.ts +9 -4
  117. package/dist/data-plane/server/indexing/plugins/starter-pack.d.ts.map +1 -1
  118. package/dist/data-plane/server/indexing/plugins/starter-pack.js.map +1 -1
  119. package/dist/data-plane/server/indexing/plugins/status.d.ts +1 -1
  120. package/dist/data-plane/server/indexing/plugins/status.d.ts.map +1 -1
  121. package/dist/data-plane/server/indexing/plugins/status.js.map +1 -1
  122. package/dist/data-plane/server/indexing/plugins/thread-gate.d.ts +1 -1
  123. package/dist/data-plane/server/indexing/plugins/thread-gate.d.ts.map +1 -1
  124. package/dist/data-plane/server/indexing/plugins/thread-gate.js.map +1 -1
  125. package/dist/data-plane/server/indexing/plugins/verification.d.ts +12 -4
  126. package/dist/data-plane/server/indexing/plugins/verification.d.ts.map +1 -1
  127. package/dist/data-plane/server/indexing/plugins/verification.js.map +1 -1
  128. package/dist/data-plane/server/indexing/processor.d.ts +1 -1
  129. package/dist/data-plane/server/indexing/processor.d.ts.map +1 -1
  130. package/dist/data-plane/server/indexing/processor.js.map +1 -1
  131. package/dist/data-plane/server/routes/blocks.js +22 -14
  132. package/dist/data-plane/server/routes/blocks.js.map +1 -1
  133. package/dist/data-plane/server/routes/feed-gens.js +2 -2
  134. package/dist/data-plane/server/routes/feed-gens.js.map +1 -1
  135. package/dist/data-plane/server/routes/feeds.js +18 -16
  136. package/dist/data-plane/server/routes/feeds.js.map +1 -1
  137. package/dist/data-plane/server/routes/labels.js +1 -1
  138. package/dist/data-plane/server/routes/labels.js.map +1 -1
  139. package/dist/data-plane/server/routes/mutes.js +2 -2
  140. package/dist/data-plane/server/routes/mutes.js.map +1 -1
  141. package/dist/data-plane/server/routes/notifs.d.ts.map +1 -1
  142. package/dist/data-plane/server/routes/notifs.js +11 -17
  143. package/dist/data-plane/server/routes/notifs.js.map +1 -1
  144. package/dist/data-plane/server/routes/relationships.js.map +1 -1
  145. package/dist/data-plane/server/routes/search.js +2 -2
  146. package/dist/data-plane/server/routes/search.js.map +1 -1
  147. package/dist/data-plane/server/routes/suggestions.js +2 -2
  148. package/dist/data-plane/server/routes/suggestions.js.map +1 -1
  149. package/dist/data-plane/server/subscription.d.ts +13 -12
  150. package/dist/data-plane/server/subscription.d.ts.map +1 -1
  151. package/dist/data-plane/server/subscription.js +59 -26
  152. package/dist/data-plane/server/subscription.js.map +1 -1
  153. package/dist/data-plane/server/util.d.ts +31 -23
  154. package/dist/data-plane/server/util.d.ts.map +1 -1
  155. package/dist/feature-gates/index.d.ts +2 -1
  156. package/dist/feature-gates/index.d.ts.map +1 -1
  157. package/dist/feature-gates/index.js +9 -6
  158. package/dist/feature-gates/index.js.map +1 -1
  159. package/dist/feature-gates/metrics.d.ts +3 -3
  160. package/dist/feature-gates/metrics.d.ts.map +1 -1
  161. package/dist/feature-gates/metrics.js +8 -8
  162. package/dist/feature-gates/metrics.js.map +1 -1
  163. package/dist/index.d.ts +1 -0
  164. package/dist/index.d.ts.map +1 -1
  165. package/dist/index.js +16 -7
  166. package/dist/index.js.map +1 -1
  167. package/dist/lexicons/app/bsky/notification/defs.defs.d.ts +5 -0
  168. package/dist/lexicons/app/bsky/notification/defs.defs.d.ts.map +1 -1
  169. package/dist/lexicons/app/bsky/notification/defs.defs.js +1 -0
  170. package/dist/lexicons/app/bsky/notification/defs.defs.js.map +1 -1
  171. package/dist/lexicons/chat/bsky/notification/defs.d.ts +2 -0
  172. package/dist/lexicons/chat/bsky/notification/defs.d.ts.map +1 -0
  173. package/dist/lexicons/chat/bsky/notification/defs.defs.d.ts +20 -0
  174. package/dist/lexicons/chat/bsky/notification/defs.defs.d.ts.map +1 -0
  175. package/dist/lexicons/chat/bsky/notification/defs.defs.js +19 -0
  176. package/dist/lexicons/chat/bsky/notification/defs.defs.js.map +1 -0
  177. package/dist/lexicons/chat/bsky/notification/defs.js +5 -0
  178. package/dist/lexicons/chat/bsky/notification/defs.js.map +1 -0
  179. package/dist/lexicons/chat/bsky/notification/getPreferences.d.ts +3 -0
  180. package/dist/lexicons/chat/bsky/notification/getPreferences.d.ts.map +1 -0
  181. package/dist/lexicons/chat/bsky/notification/getPreferences.defs.d.ts +18 -0
  182. package/dist/lexicons/chat/bsky/notification/getPreferences.defs.d.ts.map +1 -0
  183. package/dist/lexicons/chat/bsky/notification/getPreferences.defs.js +16 -0
  184. package/dist/lexicons/chat/bsky/notification/getPreferences.defs.js.map +1 -0
  185. package/dist/lexicons/chat/bsky/notification/getPreferences.js +6 -0
  186. package/dist/lexicons/chat/bsky/notification/getPreferences.js.map +1 -0
  187. package/dist/lexicons/chat/bsky/notification/putPreferences.d.ts +3 -0
  188. package/dist/lexicons/chat/bsky/notification/putPreferences.d.ts.map +1 -0
  189. package/dist/lexicons/chat/bsky/notification/putPreferences.defs.d.ts +27 -0
  190. package/dist/lexicons/chat/bsky/notification/putPreferences.defs.d.ts.map +1 -0
  191. package/dist/lexicons/chat/bsky/notification/putPreferences.defs.js +22 -0
  192. package/dist/lexicons/chat/bsky/notification/putPreferences.defs.js.map +1 -0
  193. package/dist/lexicons/chat/bsky/notification/putPreferences.js +6 -0
  194. package/dist/lexicons/chat/bsky/notification/putPreferences.js.map +1 -0
  195. package/dist/lexicons/chat/bsky/notification.d.ts +4 -0
  196. package/dist/lexicons/chat/bsky/notification.d.ts.map +1 -0
  197. package/dist/lexicons/chat/bsky/notification.js +7 -0
  198. package/dist/lexicons/chat/bsky/notification.js.map +1 -0
  199. package/dist/lexicons/chat/bsky.d.ts +1 -0
  200. package/dist/lexicons/chat/bsky.d.ts.map +1 -1
  201. package/dist/lexicons/chat/bsky.js +1 -0
  202. package/dist/lexicons/chat/bsky.js.map +1 -1
  203. package/dist/lexicons/tools/ozone/report/defs.defs.d.ts +4 -0
  204. package/dist/lexicons/tools/ozone/report/defs.defs.d.ts.map +1 -1
  205. package/dist/lexicons/tools/ozone/report/defs.defs.js +2 -0
  206. package/dist/lexicons/tools/ozone/report/defs.defs.js.map +1 -1
  207. package/dist/lexicons/tools/ozone/report/queryActivities.d.ts +3 -0
  208. package/dist/lexicons/tools/ozone/report/queryActivities.d.ts.map +1 -0
  209. package/dist/lexicons/tools/ozone/report/queryActivities.defs.d.ts +42 -0
  210. package/dist/lexicons/tools/ozone/report/queryActivities.defs.d.ts.map +1 -0
  211. package/dist/lexicons/tools/ozone/report/queryActivities.defs.js +31 -0
  212. package/dist/lexicons/tools/ozone/report/queryActivities.defs.js.map +1 -0
  213. package/dist/lexicons/tools/ozone/report/queryActivities.js +6 -0
  214. package/dist/lexicons/tools/ozone/report/queryActivities.js.map +1 -0
  215. package/dist/lexicons/tools/ozone/report.d.ts +1 -0
  216. package/dist/lexicons/tools/ozone/report.d.ts.map +1 -1
  217. package/dist/lexicons/tools/ozone/report.js +1 -0
  218. package/dist/lexicons/tools/ozone/report.js.map +1 -1
  219. package/dist/proto/bsky_pb.d.ts +47 -53
  220. package/dist/proto/bsky_pb.d.ts.map +1 -1
  221. package/dist/proto/bsky_pb.js +62 -71
  222. package/dist/proto/bsky_pb.js.map +1 -1
  223. package/package.json +13 -13
  224. package/proto/bsky.proto +19 -17
  225. package/src/api/app/bsky/actor/searchActors.ts +17 -6
  226. package/src/api/app/bsky/actor/searchActorsTypeahead.ts +16 -8
  227. package/src/api/app/bsky/feed/searchPosts.ts +12 -5
  228. package/src/api/app/bsky/graph/searchStarterPacks.ts +14 -5
  229. package/src/api/app/bsky/notification/putPreferencesV2.ts +4 -1
  230. package/src/api/app/bsky/notification/util.ts +7 -11
  231. package/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +9 -2
  232. package/src/api/blob-dispatcher.ts +12 -8
  233. package/src/api/blob-resolver.ts +0 -1
  234. package/src/api/util.ts +17 -0
  235. package/src/config.ts +9 -0
  236. package/src/data-plane/bsync/index.ts +12 -10
  237. package/src/data-plane/server/background.ts +49 -18
  238. package/src/data-plane/server/db/db.ts +1 -1
  239. package/src/data-plane/server/db/migrations/20230627T212437895Z-optional-handle.ts +2 -4
  240. package/src/data-plane/server/db/migrations/provider.ts +2 -1
  241. package/src/data-plane/server/db/pagination.ts +15 -15
  242. package/src/data-plane/server/db/util.ts +8 -5
  243. package/src/data-plane/server/index.ts +12 -10
  244. package/src/data-plane/server/indexing/index.ts +1 -1
  245. package/src/data-plane/server/indexing/plugins/block.ts +4 -1
  246. package/src/data-plane/server/indexing/plugins/chat-declaration.ts +4 -1
  247. package/src/data-plane/server/indexing/plugins/feed-generator.ts +4 -1
  248. package/src/data-plane/server/indexing/plugins/follow.ts +4 -1
  249. package/src/data-plane/server/indexing/plugins/germ-declaration.ts +4 -1
  250. package/src/data-plane/server/indexing/plugins/labeler.ts +4 -1
  251. package/src/data-plane/server/indexing/plugins/like.ts +4 -1
  252. package/src/data-plane/server/indexing/plugins/list-block.ts +4 -1
  253. package/src/data-plane/server/indexing/plugins/list-item.ts +4 -1
  254. package/src/data-plane/server/indexing/plugins/list.ts +4 -1
  255. package/src/data-plane/server/indexing/plugins/notif-declaration.ts +4 -1
  256. package/src/data-plane/server/indexing/plugins/post-gate.ts +4 -1
  257. package/src/data-plane/server/indexing/plugins/post.ts +9 -5
  258. package/src/data-plane/server/indexing/plugins/profile.ts +4 -1
  259. package/src/data-plane/server/indexing/plugins/repost.ts +4 -1
  260. package/src/data-plane/server/indexing/plugins/starter-pack.ts +4 -1
  261. package/src/data-plane/server/indexing/plugins/status.ts +4 -1
  262. package/src/data-plane/server/indexing/plugins/thread-gate.ts +4 -1
  263. package/src/data-plane/server/indexing/plugins/verification.ts +4 -1
  264. package/src/data-plane/server/indexing/processor.ts +1 -1
  265. package/src/data-plane/server/routes/blocks.ts +30 -24
  266. package/src/data-plane/server/routes/feed-gens.ts +2 -2
  267. package/src/data-plane/server/routes/feeds.ts +23 -19
  268. package/src/data-plane/server/routes/labels.ts +2 -2
  269. package/src/data-plane/server/routes/mutes.ts +8 -6
  270. package/src/data-plane/server/routes/notifs.ts +15 -26
  271. package/src/data-plane/server/routes/relationships.ts +4 -2
  272. package/src/data-plane/server/routes/search.ts +2 -2
  273. package/src/data-plane/server/routes/suggestions.ts +2 -2
  274. package/src/data-plane/server/subscription.ts +74 -31
  275. package/src/feature-gates/index.ts +10 -6
  276. package/src/feature-gates/metrics.test.ts +12 -12
  277. package/src/feature-gates/metrics.ts +8 -8
  278. package/src/index.ts +16 -9
  279. package/tests/_util.ts +8 -25
  280. package/tests/admin/admin-auth.test.ts +2 -2
  281. package/tests/admin/moderation.test.ts +1 -1
  282. package/tests/auth.test.ts +4 -6
  283. package/tests/blob-resolver.test.ts +4 -5
  284. package/tests/data-plane/db.test.ts +1 -1
  285. package/tests/data-plane/duplicate-records.test.ts +1 -1
  286. package/tests/data-plane/handle-invalidation.test.ts +2 -2
  287. package/tests/data-plane/indexing.test.ts +24 -21
  288. package/tests/data-plane/subscription.test.ts +3 -3
  289. package/tests/data-plane/thread-mutes.test.ts +2 -2
  290. package/tests/entryway-auth.test.ts +4 -5
  291. package/tests/feed-generation.test.ts +5 -5
  292. package/tests/image/server.test.ts +1 -1
  293. package/tests/label-hydration.test.ts +3 -5
  294. package/tests/postgates.test.ts +3 -6
  295. package/tests/query-labels.test.ts +3 -5
  296. package/tests/redis-cache.test.ts +1 -3
  297. package/tests/server.test.ts +11 -16
  298. package/tests/sitemap.test.ts +3 -4
  299. package/tests/stash.test.ts +12 -8
  300. package/tests/utils.test.ts +3 -13
  301. package/tests/views/account-deactivation.test.ts +3 -5
  302. package/tests/views/actor-likes.test.ts +3 -5
  303. package/tests/views/actor-search.test.ts +6 -7
  304. package/tests/views/age-assurance-v2.test.ts +9 -6
  305. package/tests/views/age-assurance.test.ts +30 -36
  306. package/tests/views/author-feed.test.ts +4 -6
  307. package/tests/views/block-lists.test.ts +3 -5
  308. package/tests/views/blocks.test.ts +3 -5
  309. package/tests/views/bookmarks.test.ts +4 -4
  310. package/tests/views/drafts.test.ts +7 -14
  311. package/tests/views/feed-hidden-replies.test.ts +3 -6
  312. package/tests/views/feed-view-post.test.ts +3 -6
  313. package/tests/views/follows.test.ts +4 -6
  314. package/tests/views/get-config.test.ts +4 -7
  315. package/tests/views/get-suggested-onboarding-users.test.ts +11 -9
  316. package/tests/views/get-suggested-starter-packs.test.ts +11 -9
  317. package/tests/views/get-trends.test.ts +15 -9
  318. package/tests/views/internal-actor.test.ts +3 -6
  319. package/tests/views/known-followers.test.ts +3 -6
  320. package/tests/views/labeler-service.test.ts +3 -5
  321. package/tests/views/labels-needs-review.test.ts +3 -6
  322. package/tests/views/labels-takedown.test.ts +3 -4
  323. package/tests/views/likes.test.ts +4 -6
  324. package/tests/views/list-feed.test.ts +3 -5
  325. package/tests/views/lists.test.ts +3 -5
  326. package/tests/views/mute-lists.test.ts +3 -5
  327. package/tests/views/mutes.test.ts +4 -5
  328. package/tests/views/notifications.test.ts +12 -11
  329. package/tests/views/post-search.test.ts +3 -24
  330. package/tests/views/posts-debug.test.ts +11 -6
  331. package/tests/views/posts.test.ts +3 -4
  332. package/tests/views/profile-debug.test.ts +11 -5
  333. package/tests/views/profile.test.ts +11 -5
  334. package/tests/views/quotes.test.ts +4 -6
  335. package/tests/views/reposts.test.ts +4 -6
  336. package/tests/views/starter-packs.test.ts +3 -6
  337. package/tests/views/suggestions.test.ts +9 -13
  338. package/tests/views/thread-v2.test.ts +3 -5
  339. package/tests/views/thread.test.ts +3 -7
  340. package/tests/views/threadgating.test.ts +3 -5
  341. package/tests/views/timeline.test.ts +4 -5
  342. package/tests/views/verification.test.ts +4 -6
  343. package/tsconfig.build.tsbuildinfo +1 -1
  344. package/vitest.config.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/bsky",
3
- "version": "0.0.242",
3
+ "version": "0.0.244",
4
4
  "license": "MIT",
5
5
  "description": "Reference implementation of app.bsky App View (Bluesky API)",
6
6
  "keywords": [
@@ -35,7 +35,7 @@
35
35
  "ioredis": "^5.3.2",
36
36
  "jose": "^5.0.1",
37
37
  "key-encoder": "^2.0.3",
38
- "kysely": "^0.22.0",
38
+ "kysely": "^0.29.2",
39
39
  "leo-profanity": "^1.8.0",
40
40
  "murmurhash": "^2.0.1",
41
41
  "p-queue": "^8.0.0",
@@ -46,20 +46,20 @@
46
46
  "structured-headers": "^1.0.1",
47
47
  "typed-emitter": "^2.1.0",
48
48
  "uint8arrays": "^5.0.0",
49
- "undici": "^6.19.8",
49
+ "undici": "^8.5.0",
50
50
  "zod": "3.23.8",
51
- "@atproto-labs/fetch-node": "^0.3.1",
52
- "@atproto/api": "^0.20.16",
53
- "@atproto-labs/xrpc-utils": "^0.1.1",
51
+ "@atproto-labs/fetch-node": "^0.3.2",
52
+ "@atproto/api": "^0.20.17",
54
53
  "@atproto/crypto": "^0.5.1",
55
54
  "@atproto/common": "^0.6.3",
56
- "@atproto/identity": "^0.5.1",
55
+ "@atproto/did": "^0.5.1",
56
+ "@atproto-labs/xrpc-utils": "^0.1.1",
57
57
  "@atproto/lex": "^0.1.4",
58
58
  "@atproto/repo": "^0.10.1",
59
- "@atproto/did": "^0.5.1",
60
- "@atproto/sync": "^0.3.2",
61
- "@atproto/xrpc-server": "^0.11.2",
62
- "@atproto/syntax": "^0.6.2"
59
+ "@atproto/identity": "^0.5.1",
60
+ "@atproto/sync": "^0.3.3",
61
+ "@atproto/syntax": "^0.6.2",
62
+ "@atproto/xrpc-server": "^0.11.2"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@bufbuild/buf": "^1.28.1",
@@ -69,11 +69,11 @@
69
69
  "@types/cors": "^2.8.12",
70
70
  "@types/express": "^4.17.13",
71
71
  "@types/express-serve-static-core": "^4.17.36",
72
- "@types/pg": "^8.6.6",
72
+ "@types/pg": "^8.15.5",
73
73
  "@types/qs": "^6.9.7",
74
74
  "ts-node": "^10.8.2",
75
75
  "vitest": "^4.0.16",
76
- "@atproto/pds": "^0.5.5"
76
+ "@atproto/pds": "^0.5.7"
77
77
  },
78
78
  "type": "module",
79
79
  "exports": {
package/proto/bsky.proto CHANGED
@@ -815,20 +815,12 @@ message NotificationPreference {
815
815
  NotificationChannelPush push = 2;
816
816
  }
817
817
 
818
- enum ChatNotificationInclude {
819
- CHAT_NOTIFICATION_INCLUDE_UNSPECIFIED = 0;
820
- CHAT_NOTIFICATION_INCLUDE_ALL = 1;
821
- CHAT_NOTIFICATION_INCLUDE_ACCEPTED = 2;
822
- }
823
-
824
- message ChatNotificationPreference {
825
- ChatNotificationInclude include = 1;
826
- NotificationChannelPush push = 2;
827
- }
828
-
829
818
  message NotificationPreferences {
830
819
  bytes entry = 1;
831
- ChatNotificationPreference chat = 2;
820
+
821
+ reserved 2; // formerly "chat". This is now stored on the chat service.
822
+ reserved "chat";
823
+
832
824
  FilterableNotificationPreference follow = 3;
833
825
  FilterableNotificationPreference like = 4;
834
826
  FilterableNotificationPreference like_via_repost = 5;
@@ -1144,10 +1136,10 @@ enum SearchQueryLanguage {
1144
1136
  SEARCH_QUERY_LANGUAGE_ZH = 2; // Chinese (smartcn)
1145
1137
  SEARCH_QUERY_LANGUAGE_KO = 3; // Korean (nori)
1146
1138
  SEARCH_QUERY_LANGUAGE_TH = 4; // Thai
1139
+ SEARCH_QUERY_LANGUAGE_AR = 5; // Arabic
1147
1140
  }
1148
1141
 
1149
- // Shared request params
1150
-
1142
+ // Shared request params for paginated methods
1151
1143
  message SearchParams {
1152
1144
  string query = 1;
1153
1145
  string viewer = 2;
@@ -1157,6 +1149,13 @@ message SearchParams {
1157
1149
  string cursor = 4;
1158
1150
  }
1159
1151
 
1152
+ // Shared params for typeahead-style searches, which aren't paginated.
1153
+ message SearchTypeaheadParams {
1154
+ string query = 1;
1155
+ string viewer = 2;
1156
+ int32 limit = 3;
1157
+ }
1158
+
1160
1159
  // Shared result types
1161
1160
 
1162
1161
  // SearchRecordResult represents a generic result hit corresponding to a record.
@@ -1246,6 +1245,11 @@ message SearchPostsV2Request {
1246
1245
  message SearchPostsV2Response {
1247
1246
  repeated SearchRecordResult posts = 1;
1248
1247
  PageInfo page_info = 2;
1248
+ // Detected CJK/Thai/Arabic languages of the query, usually one. Han-only text
1249
+ // returns ["zh", "ja"] since it's ambiguous between Chinese and Japanese.
1250
+ // set query_language on the request to disambiguate.
1251
+ // Currently left empty for other scripts (e.g. Latin-based languages like English).
1252
+ repeated string detected_query_languages = 3;
1249
1253
  }
1250
1254
 
1251
1255
  message SearchActorsV2Request {
@@ -1258,9 +1262,7 @@ message SearchActorsV2Response {
1258
1262
  }
1259
1263
 
1260
1264
  message SearchActorsTypeaheadRequest {
1261
- string viewer = 1;
1262
- string query = 2;
1263
- int32 limit = 3;
1265
+ SearchTypeaheadParams params = 1;
1264
1266
  }
1265
1267
 
1266
1268
  message SearchActorsTypeaheadResponse {
@@ -14,7 +14,7 @@ import {
14
14
  createPipeline,
15
15
  } from '../../../../pipeline.js'
16
16
  import { Views } from '../../../../views/index.js'
17
- import { resHeaders } from '../../../util.js'
17
+ import { resHeaders, resolveSearchV2Override } from '../../../util.js'
18
18
 
19
19
  export default function (server: Server, ctx: AppContext) {
20
20
  const searchActors = createPipeline(
@@ -41,7 +41,14 @@ export default function (server: Server, ctx: AppContext) {
41
41
  }),
42
42
  ),
43
43
  })
44
- const results = await searchActors({ ...params, hydrateCtx }, ctx)
44
+ const results = await searchActors(
45
+ {
46
+ ...params,
47
+ hydrateCtx,
48
+ isV2Override: resolveSearchV2Override(req, ctx.cfg),
49
+ },
50
+ ctx,
51
+ )
45
52
  return {
46
53
  encoding: 'application/json',
47
54
  body: results,
@@ -109,9 +116,10 @@ const skeletonV2 = async (
109
116
  }
110
117
 
111
118
  const skeleton = async (input: SkeletonFnInput<Context, Params>) => {
112
- const useV2 = input.params.hydrateCtx.features.checkGate(
113
- input.params.hydrateCtx.features.Gate.SearchV2Enable,
114
- )
119
+ const useV2 =
120
+ input.params.hydrateCtx.features.checkGate(
121
+ input.params.hydrateCtx.features.Gate.SearchV2Enable,
122
+ ) || input.params.isV2Override
115
123
  const skeletonFn = useV2 ? skeletonV2 : skeletonV1
116
124
  return skeletonFn(input)
117
125
  }
@@ -151,7 +159,10 @@ type Context = {
151
159
  searchClient?: Client
152
160
  }
153
161
 
154
- type Params = app.bsky.actor.searchActors.$Params & { hydrateCtx: HydrateCtx }
162
+ type Params = app.bsky.actor.searchActors.$Params & {
163
+ hydrateCtx: HydrateCtx
164
+ isV2Override: boolean
165
+ }
155
166
 
156
167
  type Skeleton = {
157
168
  dids: DidString[]
@@ -13,7 +13,7 @@ import {
13
13
  createPipeline,
14
14
  } from '../../../../pipeline.js'
15
15
  import { Views } from '../../../../views/index.js'
16
- import { resHeaders } from '../../../util.js'
16
+ import { resHeaders, resolveSearchV2Override } from '../../../util.js'
17
17
 
18
18
  export default function (server: Server, ctx: AppContext) {
19
19
  const searchActorsTypeahead = createPipeline(
@@ -38,7 +38,11 @@ export default function (server: Server, ctx: AppContext) {
38
38
  ),
39
39
  })
40
40
  const results = await searchActorsTypeahead(
41
- { ...params, hydrateCtx },
41
+ {
42
+ ...params,
43
+ hydrateCtx,
44
+ isV2Override: resolveSearchV2Override(req, ctx.cfg),
45
+ },
42
46
  ctx,
43
47
  )
44
48
  return {
@@ -91,9 +95,11 @@ const skeletonV2 = async (
91
95
  const term = params.q ?? params.term ?? ''
92
96
 
93
97
  const res = await ctx.dataplane.searchActorsTypeahead({
94
- viewer: params.hydrateCtx.viewer ?? undefined,
95
- query: term,
96
- limit: params.limit,
98
+ params: {
99
+ query: term,
100
+ viewer: params.hydrateCtx.viewer ?? undefined,
101
+ limit: params.limit,
102
+ },
97
103
  })
98
104
  return {
99
105
  dids: res.actors.map(({ did }) => did as DidString),
@@ -101,9 +107,10 @@ const skeletonV2 = async (
101
107
  }
102
108
 
103
109
  const skeleton = async (input: SkeletonFnInput<Context, Params>) => {
104
- const useV2 = input.params.hydrateCtx.features.checkGate(
105
- input.params.hydrateCtx.features.Gate.SearchV2Enable,
106
- )
110
+ const useV2 =
111
+ input.params.hydrateCtx.features.checkGate(
112
+ input.params.hydrateCtx.features.Gate.SearchV2Enable,
113
+ ) || input.params.isV2Override
107
114
  const skeletonFn = useV2 ? skeletonV2 : skeletonV1
108
115
  return skeletonFn(input)
109
116
  }
@@ -149,6 +156,7 @@ type Context = {
149
156
 
150
157
  type Params = app.bsky.actor.searchActorsTypeahead.$Params & {
151
158
  hydrateCtx: HydrateCtx
159
+ isV2Override: boolean
152
160
  }
153
161
 
154
162
  type Skeleton = {
@@ -22,7 +22,7 @@ import {
22
22
  import { SearchSortOrder } from '../../../../proto/bsky_pb.js'
23
23
  import { uriToDid as creatorFromUri } from '../../../../util/uris.js'
24
24
  import { Views } from '../../../../views/index.js'
25
- import { resHeaders } from '../../../util.js'
25
+ import { resHeaders, resolveSearchV2Override } from '../../../util.js'
26
26
 
27
27
  export default function (server: Server, ctx: AppContext) {
28
28
  const searchPosts = createPipeline(
@@ -50,7 +50,12 @@ export default function (server: Server, ctx: AppContext) {
50
50
  ),
51
51
  })
52
52
  const results = await searchPosts(
53
- { ...params, hydrateCtx, isModService },
53
+ {
54
+ ...params,
55
+ hydrateCtx,
56
+ isModService,
57
+ isV2Override: resolveSearchV2Override(req, ctx.cfg),
58
+ },
54
59
  ctx,
55
60
  )
56
61
  return {
@@ -146,9 +151,10 @@ const skeletonV2 = async (
146
151
  }
147
152
 
148
153
  const skeleton = async (input: SkeletonFnInput<Context, Params>) => {
149
- const useV2 = input.params.hydrateCtx.features.checkGate(
150
- input.params.hydrateCtx.features.Gate.SearchV2Enable,
151
- )
154
+ const useV2 =
155
+ input.params.hydrateCtx.features.checkGate(
156
+ input.params.hydrateCtx.features.Gate.SearchV2Enable,
157
+ ) || input.params.isV2Override
152
158
  const skeletonFn = useV2 ? skeletonV2 : skeletonV1
153
159
  return skeletonFn(input)
154
160
  }
@@ -237,6 +243,7 @@ type Context = {
237
243
  type Params = app.bsky.feed.searchPosts.$Params & {
238
244
  hydrateCtx: HydrateCtx
239
245
  isModService: boolean
246
+ isV2Override: boolean
240
247
  }
241
248
 
242
249
  type Skeleton = {
@@ -15,7 +15,7 @@ import {
15
15
  } from '../../../../pipeline.js'
16
16
  import { uriToDid as creatorFromUri } from '../../../../util/uris.js'
17
17
  import { Views } from '../../../../views/index.js'
18
- import { resHeaders } from '../../../util.js'
18
+ import { resHeaders, resolveSearchV2Override } from '../../../util.js'
19
19
 
20
20
  export default function (server: Server, ctx: AppContext) {
21
21
  const searchStarterPacks = createPipeline(
@@ -42,7 +42,14 @@ export default function (server: Server, ctx: AppContext) {
42
42
  }),
43
43
  ),
44
44
  })
45
- const results = await searchStarterPacks({ ...params, hydrateCtx }, ctx)
45
+ const results = await searchStarterPacks(
46
+ {
47
+ ...params,
48
+ hydrateCtx,
49
+ isV2Override: resolveSearchV2Override(req, ctx.cfg),
50
+ },
51
+ ctx,
52
+ )
46
53
  return {
47
54
  encoding: 'application/json',
48
55
  body: results,
@@ -107,9 +114,10 @@ const skeletonV2 = async (
107
114
  }
108
115
 
109
116
  const skeleton = async (input: SkeletonFnInput<Context, Params>) => {
110
- const useV2 = input.params.hydrateCtx.features.checkGate(
111
- input.params.hydrateCtx.features.Gate.SearchV2Enable,
112
- )
117
+ const useV2 =
118
+ input.params.hydrateCtx.features.checkGate(
119
+ input.params.hydrateCtx.features.Gate.SearchV2Enable,
120
+ ) || input.params.isV2Override
113
121
  const skeletonFn = useV2 ? skeletonV2 : skeletonV1
114
122
  return skeletonFn(input)
115
123
  }
@@ -152,6 +160,7 @@ type Context = {
152
160
 
153
161
  type Params = app.bsky.graph.searchStarterPacks.$Params & {
154
162
  hydrateCtx: HydrateCtx
163
+ isV2Override: boolean
155
164
  }
156
165
 
157
166
  type Skeleton = {
@@ -5,7 +5,7 @@ import { AppContext } from '../../../../context.js'
5
5
  import { app } from '../../../../lexicons/index.js'
6
6
  import { GetNotificationPreferencesResponse } from '../../../../proto/bsky_pb.js'
7
7
  import { Namespaces } from '../../../../stash.js'
8
- import { protobufToLex } from './util.js'
8
+ import { DEFAULT_CHAT_PREFERENCE, protobufToLex } from './util.js'
9
9
 
10
10
  export default function (server: Server, ctx: AppContext) {
11
11
  server.add(app.bsky.notification.putPreferencesV2, {
@@ -57,5 +57,8 @@ const computePreferences = async (
57
57
 
58
58
  const currentPreferences = protobufToLex(res.preferences[0])
59
59
  const preferences = { ...currentPreferences, ...input.body }
60
+ // NOTE: See the deprecation notice on the lexicon. This field returns a static default value and shouldn't be used.
61
+ // Use the chat.bsky.notification.defs#preferences type instead.
62
+ preferences.chat = DEFAULT_CHAT_PREFERENCE
60
63
  return preferences
61
64
  }
@@ -1,7 +1,5 @@
1
1
  import { app } from '../../../../lexicons/index.js'
2
2
  import {
3
- ChatNotificationInclude,
4
- ChatNotificationPreference,
5
3
  FilterableNotificationPreference,
6
4
  NotificationInclude,
7
5
  NotificationPreference,
@@ -71,15 +69,11 @@ const ensurePreferences = (
71
69
  }
72
70
  }
73
71
 
74
- const protobufChatPreferenceToLex = (
75
- p?: DeepPartial<ChatNotificationPreference>,
76
- ): Partial<app.bsky.notification.defs.ChatPreference> => {
77
- return {
78
- include:
79
- p?.include === ChatNotificationInclude.ACCEPTED ? 'accepted' : 'all',
80
- push: p?.push?.enabled,
72
+ export const DEFAULT_CHAT_PREFERENCE: app.bsky.notification.defs.ChatPreference =
73
+ {
74
+ include: 'all',
75
+ push: true,
81
76
  }
82
- }
83
77
 
84
78
  const protobufFilterablePreferenceToLex = (
85
79
  p?: DeepPartial<FilterableNotificationPreference>,
@@ -104,7 +98,9 @@ export const protobufToLex = (
104
98
  res: DeepPartial<NotificationPreferences>,
105
99
  ): app.bsky.notification.defs.Preferences => {
106
100
  return ensurePreferences({
107
- chat: protobufChatPreferenceToLex(res.chat),
101
+ // NOTE: See the deprecation notice on the lexicon. This field returns a static default value and shouldn't be used.
102
+ // Use the chat.bsky.notification.defs#preferences type instead.
103
+ chat: DEFAULT_CHAT_PREFERENCE,
108
104
  follow: protobufFilterablePreferenceToLex(res.follow),
109
105
  like: protobufFilterablePreferenceToLex(res.like),
110
106
  likeViaRepost: protobufFilterablePreferenceToLex(res.likeViaRepost),
@@ -4,7 +4,11 @@ import { Server } from '@atproto/xrpc-server'
4
4
  import { AppContext } from '../../../../context.js'
5
5
  import { parseString } from '../../../../hydration/util.js'
6
6
  import { app } from '../../../../lexicons/index.js'
7
- import { clearlyBadCursor, resHeaders } from '../../../util.js'
7
+ import {
8
+ clearlyBadCursor,
9
+ resHeaders,
10
+ resolveSearchV2Override,
11
+ } from '../../../util.js'
8
12
 
9
13
  // THIS IS A TEMPORARY UNSPECCED ROUTE
10
14
  // @TODO currently mirrors getSuggestedFeeds and ignores the "query" param.
@@ -37,9 +41,12 @@ export default function (server: Server, ctx: AppContext) {
37
41
  let uris: AtUriString[]
38
42
  let cursor: string | undefined
39
43
 
44
+ const isV2Override = resolveSearchV2Override(req, ctx.cfg)
45
+
40
46
  const query = params.query?.trim() ?? ''
41
47
  if (query) {
42
- const useV2 = features.checkGate(features.Gate.SearchV2Enable)
48
+ const useV2 =
49
+ features.checkGate(features.Gate.SearchV2Enable) || isV2Override
43
50
  if (useV2) {
44
51
  const res = await ctx.dataplane.searchFeedGeneratorsV2({
45
52
  params: {
@@ -1,4 +1,4 @@
1
- import { Agent, Dispatcher, Pool, RetryAgent } from 'undici'
1
+ import { Agent, Dispatcher, Pool, interceptors } from 'undici'
2
2
  import { isUnicastIp, unicastLookup } from '@atproto-labs/fetch-node'
3
3
  import { ServerConfig } from '../config.js'
4
4
  import { RETRYABLE_HTTP_STATUS_CODES } from '../util/retry.js'
@@ -27,11 +27,15 @@ export function createBlobDispatcher(cfg: ServerConfig): Dispatcher {
27
27
  },
28
28
  })
29
29
 
30
- return cfg.proxyMaxRetries > 0
31
- ? new RetryAgent(baseDispatcher, {
32
- statusCodes: [...RETRYABLE_HTTP_STATUS_CODES],
33
- methods: ['GET', 'HEAD'],
34
- maxRetries: cfg.proxyMaxRetries,
35
- })
36
- : baseDispatcher
30
+ return baseDispatcher.compose(
31
+ interceptors.redirect({
32
+ maxRedirections: 10,
33
+ throwOnMaxRedirect: true,
34
+ }),
35
+ interceptors.retry({
36
+ statusCodes: [...RETRYABLE_HTTP_STATUS_CODES],
37
+ methods: ['GET', 'HEAD'],
38
+ maxRetries: cfg.proxyMaxRetries,
39
+ }),
40
+ )
37
41
  }
@@ -197,7 +197,6 @@ export async function streamBlob(
197
197
  path: url.pathname + url.search,
198
198
  headers,
199
199
  signal: options.signal,
200
- maxRedirections: 10,
201
200
  },
202
201
  (upstream) => {
203
202
  headersReceived = true
package/src/api/util.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { IncomingHttpHeaders } from 'node:http'
2
+ import { ServerConfig } from '../config.js'
1
3
  import { ParsedLabelers, formatLabelerHeader } from '../util.js'
2
4
 
3
5
  export const BSKY_USER_AGENT = 'BskyAppView'
@@ -26,3 +28,18 @@ export const clearlyBadCursor = (cursor?: string) => {
26
28
  // hallmark of v1 cursor, highly unlikely in v2 cursors based on time or rkeys
27
29
  return !!cursor?.includes('::')
28
30
  }
31
+
32
+ // @TEMPORARY backdoor to force search v2 via a request header, gated by the
33
+ // BSKY_SEARCH_V2_OVERRIDE_HEADER env var. Remove once search v2 is fully rolled out.
34
+ const SEARCH_V2_OVERRIDE_HEADER = 'x-bsky-search-v2-override'
35
+
36
+ export const resolveSearchV2Override = (
37
+ req: { headers: IncomingHttpHeaders },
38
+ cfg: ServerConfig,
39
+ ): boolean => {
40
+ const expected = cfg.searchV2OverrideHeader
41
+ if (!expected) return false
42
+ const value = req.headers[SEARCH_V2_OVERRIDE_HEADER]
43
+ const header = Array.isArray(value) ? value.join(',') : value
44
+ return header === expected
45
+ }
package/src/config.ts CHANGED
@@ -110,6 +110,7 @@ export interface ServerConfigValues {
110
110
  kws?: KwsConfig
111
111
  debugFieldAllowedDids: Set<string>
112
112
  draftsLimit: number
113
+ searchV2OverrideHeader?: string
113
114
  }
114
115
 
115
116
  export class ServerConfig {
@@ -331,6 +332,9 @@ export class ServerConfig {
331
332
  ? parseInt(process.env.BSKY_DRAFTS_LIMIT || '', 10)
332
333
  : 500
333
334
 
335
+ const searchV2OverrideHeader =
336
+ process.env.BSKY_SEARCH_V2_OVERRIDE_HEADER || undefined
337
+
334
338
  return new ServerConfig({
335
339
  version,
336
340
  debugMode,
@@ -399,6 +403,7 @@ export class ServerConfig {
399
403
  kws,
400
404
  debugFieldAllowedDids,
401
405
  draftsLimit,
406
+ searchV2OverrideHeader,
402
407
  ...noUndefinedVals(overrides ?? {}),
403
408
  })
404
409
  }
@@ -675,6 +680,10 @@ export class ServerConfig {
675
680
  get draftsLimit() {
676
681
  return this.cfg.draftsLimit
677
682
  }
683
+
684
+ get searchV2OverrideHeader() {
685
+ return this.cfg.searchV2OverrideHeader
686
+ }
678
687
  }
679
688
 
680
689
  function envList(str: string | undefined): string[] {
@@ -4,6 +4,8 @@ import http from 'node:http'
4
4
  import { ConnectRouter } from '@connectrpc/connect'
5
5
  import { expressConnectMiddleware } from '@connectrpc/connect-express'
6
6
  import express from 'express'
7
+ // eslint-disable-next-line import/default
8
+ import httpTerminator from 'http-terminator'
7
9
  import { TID } from '@atproto/common'
8
10
  import { lexParse } from '@atproto/lex'
9
11
  import { AtUri } from '@atproto/syntax'
@@ -20,7 +22,11 @@ import { Database } from '../server/db/index.js'
20
22
  import { countAll, excluded } from '../server/db/util.js'
21
23
 
22
24
  export class MockBsync {
23
- constructor(public server: http.Server) {}
25
+ private terminator: httpTerminator.HttpTerminator
26
+
27
+ constructor(public server: http.Server) {
28
+ this.terminator = httpTerminator.createHttpTerminator({ server })
29
+ }
24
30
 
25
31
  static async create(db: Database, port: number) {
26
32
  const app = express()
@@ -32,15 +38,11 @@ export class MockBsync {
32
38
  }
33
39
 
34
40
  async destroy() {
35
- return new Promise<void>((resolve, reject) => {
36
- this.server.close((err) => {
37
- if (err) {
38
- reject(err)
39
- } else {
40
- resolve()
41
- }
42
- })
43
- })
41
+ await this.terminator.terminate()
42
+ }
43
+
44
+ async [Symbol.asyncDispose]() {
45
+ await this.destroy()
44
46
  }
45
47
  }
46
48
 
@@ -1,35 +1,66 @@
1
1
  import PQueue from 'p-queue'
2
2
  import { dbLogger } from '../../logger.js'
3
- import { Database } from './db/index.js'
4
3
 
5
4
  // A simple queue for in-process, out-of-band/backgrounded work
6
5
 
7
- export class BackgroundQueue {
8
- queue: InstanceType<typeof PQueue> = new PQueue()
9
- destroyed = false
10
- constructor(public db: Database) {}
6
+ type Task<TContext> = (ctx: TContext, signal: AbortSignal) => Promise<void>
11
7
 
12
- add(task: Task) {
13
- if (this.destroyed) {
14
- return
15
- }
16
- this.queue
17
- .add(() => task(this.db))
18
- .catch((err) => {
8
+ export type BackgroundQueueOptions = NonNullable<
9
+ ConstructorParameters<typeof PQueue>[0]
10
+ > & {
11
+ concurrency: number
12
+ }
13
+
14
+ // @NOTE Keep this in sync with the BackgroundQueue in
15
+ // - packages/bsky/src/data-plane/server/background.ts
16
+ // - packages/ozone/src/background.ts
17
+ // - packages/pds/src/background.ts
18
+ export class BackgroundQueue<TContext = unknown> {
19
+ private abortController = new AbortController()
20
+ private queue: PQueue
21
+
22
+ public get signal(): AbortSignal {
23
+ return this.abortController.signal
24
+ }
25
+
26
+ public get destroyed() {
27
+ return this.signal.aborted
28
+ }
29
+
30
+ constructor(
31
+ private readonly context: TContext,
32
+ options?: BackgroundQueueOptions,
33
+ ) {
34
+ this.queue = new PQueue(options)
35
+ }
36
+
37
+ add(task: Task<TContext>) {
38
+ if (this.destroyed) return
39
+
40
+ this.queue.add<void>(async () => {
41
+ try {
42
+ // The task will receive a signal allowing it to abort if the
43
+ // backgroundQueue is destroyed.
44
+ await task(this.context, this.signal)
45
+ } catch (err) {
19
46
  dbLogger.error({ err }, 'background queue task failed')
20
- })
47
+ }
48
+ })
21
49
  }
22
50
 
23
51
  async processAll() {
24
- await this.queue.onIdle()
52
+ const { queue } = this
53
+ while (queue.size || queue.pending) await queue.onIdle()
25
54
  }
26
55
 
27
56
  // On destroy we stop accepting new tasks, but complete all pending/in-progress tasks.
28
57
  // The application calls this only once http connections have drained (tasks no longer being added).
29
58
  async destroy() {
30
- this.destroyed = true
31
- await this.queue.onIdle()
59
+ if (this.destroyed) {
60
+ dbLogger.warn('BackgroundQueue.destroy() called multiple times')
61
+ }
62
+
63
+ this.abortController.abort()
64
+ return this.processAll()
32
65
  }
33
66
  }
34
-
35
- type Task = (db: Database) => Promise<void>
@@ -3,7 +3,6 @@ import EventEmitter from 'node:events'
3
3
  import {
4
4
  Kysely,
5
5
  KyselyPlugin,
6
- Migrator,
7
6
  PluginTransformQueryArgs,
8
7
  PluginTransformResultArgs,
9
8
  PostgresDialect,
@@ -11,6 +10,7 @@ import {
11
10
  RootOperationNode,
12
11
  UnknownRow,
13
12
  } from 'kysely'
13
+ import { Migrator } from 'kysely/migration'
14
14
  // eslint-disable-next-line import/default
15
15
  import pg from 'pg'
16
16
  // eslint-disable-next-line import/no-named-as-default-member