@atproto/bsky 0.0.243 → 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 (272) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/api/app/bsky/actor/searchActorsTypeahead.js +5 -3
  3. package/dist/api/app/bsky/actor/searchActorsTypeahead.js.map +1 -1
  4. package/dist/api/app/bsky/notification/putPreferencesV2.js +4 -1
  5. package/dist/api/app/bsky/notification/putPreferencesV2.js.map +1 -1
  6. package/dist/api/app/bsky/notification/util.d.ts +1 -0
  7. package/dist/api/app/bsky/notification/util.d.ts.map +1 -1
  8. package/dist/api/app/bsky/notification/util.js +7 -7
  9. package/dist/api/app/bsky/notification/util.js.map +1 -1
  10. package/dist/api/blob-dispatcher.d.ts.map +1 -1
  11. package/dist/api/blob-dispatcher.js +9 -8
  12. package/dist/api/blob-dispatcher.js.map +1 -1
  13. package/dist/api/blob-resolver.d.ts +1 -1
  14. package/dist/api/blob-resolver.d.ts.map +1 -1
  15. package/dist/api/blob-resolver.js +0 -1
  16. package/dist/api/blob-resolver.js.map +1 -1
  17. package/dist/data-plane/bsync/index.d.ts +2 -0
  18. package/dist/data-plane/bsync/index.d.ts.map +1 -1
  19. package/dist/data-plane/bsync/index.js +7 -10
  20. package/dist/data-plane/bsync/index.js.map +1 -1
  21. package/dist/data-plane/server/background.d.ts +12 -8
  22. package/dist/data-plane/server/background.d.ts.map +1 -1
  23. package/dist/data-plane/server/background.js +32 -14
  24. package/dist/data-plane/server/background.js.map +1 -1
  25. package/dist/data-plane/server/index.d.ts +2 -0
  26. package/dist/data-plane/server/index.d.ts.map +1 -1
  27. package/dist/data-plane/server/index.js +7 -10
  28. package/dist/data-plane/server/index.js.map +1 -1
  29. package/dist/data-plane/server/indexing/index.d.ts +2 -2
  30. package/dist/data-plane/server/indexing/index.d.ts.map +1 -1
  31. package/dist/data-plane/server/indexing/index.js.map +1 -1
  32. package/dist/data-plane/server/indexing/plugins/block.d.ts +1 -1
  33. package/dist/data-plane/server/indexing/plugins/block.d.ts.map +1 -1
  34. package/dist/data-plane/server/indexing/plugins/block.js.map +1 -1
  35. package/dist/data-plane/server/indexing/plugins/chat-declaration.d.ts +1 -1
  36. package/dist/data-plane/server/indexing/plugins/chat-declaration.d.ts.map +1 -1
  37. package/dist/data-plane/server/indexing/plugins/chat-declaration.js.map +1 -1
  38. package/dist/data-plane/server/indexing/plugins/feed-generator.d.ts +1 -1
  39. package/dist/data-plane/server/indexing/plugins/feed-generator.d.ts.map +1 -1
  40. package/dist/data-plane/server/indexing/plugins/feed-generator.js.map +1 -1
  41. package/dist/data-plane/server/indexing/plugins/follow.d.ts +1 -1
  42. package/dist/data-plane/server/indexing/plugins/follow.d.ts.map +1 -1
  43. package/dist/data-plane/server/indexing/plugins/follow.js.map +1 -1
  44. package/dist/data-plane/server/indexing/plugins/germ-declaration.d.ts +1 -1
  45. package/dist/data-plane/server/indexing/plugins/germ-declaration.d.ts.map +1 -1
  46. package/dist/data-plane/server/indexing/plugins/germ-declaration.js.map +1 -1
  47. package/dist/data-plane/server/indexing/plugins/labeler.d.ts +1 -1
  48. package/dist/data-plane/server/indexing/plugins/labeler.d.ts.map +1 -1
  49. package/dist/data-plane/server/indexing/plugins/labeler.js.map +1 -1
  50. package/dist/data-plane/server/indexing/plugins/like.d.ts +1 -1
  51. package/dist/data-plane/server/indexing/plugins/like.d.ts.map +1 -1
  52. package/dist/data-plane/server/indexing/plugins/like.js.map +1 -1
  53. package/dist/data-plane/server/indexing/plugins/list-block.d.ts +1 -1
  54. package/dist/data-plane/server/indexing/plugins/list-block.d.ts.map +1 -1
  55. package/dist/data-plane/server/indexing/plugins/list-block.js.map +1 -1
  56. package/dist/data-plane/server/indexing/plugins/list-item.d.ts +1 -1
  57. package/dist/data-plane/server/indexing/plugins/list-item.d.ts.map +1 -1
  58. package/dist/data-plane/server/indexing/plugins/list-item.js.map +1 -1
  59. package/dist/data-plane/server/indexing/plugins/list.d.ts +1 -1
  60. package/dist/data-plane/server/indexing/plugins/list.d.ts.map +1 -1
  61. package/dist/data-plane/server/indexing/plugins/list.js.map +1 -1
  62. package/dist/data-plane/server/indexing/plugins/notif-declaration.d.ts +1 -1
  63. package/dist/data-plane/server/indexing/plugins/notif-declaration.d.ts.map +1 -1
  64. package/dist/data-plane/server/indexing/plugins/notif-declaration.js.map +1 -1
  65. package/dist/data-plane/server/indexing/plugins/post-gate.d.ts +1 -1
  66. package/dist/data-plane/server/indexing/plugins/post-gate.d.ts.map +1 -1
  67. package/dist/data-plane/server/indexing/plugins/post-gate.js.map +1 -1
  68. package/dist/data-plane/server/indexing/plugins/post.d.ts +1 -1
  69. package/dist/data-plane/server/indexing/plugins/post.d.ts.map +1 -1
  70. package/dist/data-plane/server/indexing/plugins/post.js.map +1 -1
  71. package/dist/data-plane/server/indexing/plugins/profile.d.ts +1 -1
  72. package/dist/data-plane/server/indexing/plugins/profile.d.ts.map +1 -1
  73. package/dist/data-plane/server/indexing/plugins/profile.js.map +1 -1
  74. package/dist/data-plane/server/indexing/plugins/repost.d.ts +1 -1
  75. package/dist/data-plane/server/indexing/plugins/repost.d.ts.map +1 -1
  76. package/dist/data-plane/server/indexing/plugins/repost.js.map +1 -1
  77. package/dist/data-plane/server/indexing/plugins/starter-pack.d.ts +1 -1
  78. package/dist/data-plane/server/indexing/plugins/starter-pack.d.ts.map +1 -1
  79. package/dist/data-plane/server/indexing/plugins/starter-pack.js.map +1 -1
  80. package/dist/data-plane/server/indexing/plugins/status.d.ts +1 -1
  81. package/dist/data-plane/server/indexing/plugins/status.d.ts.map +1 -1
  82. package/dist/data-plane/server/indexing/plugins/status.js.map +1 -1
  83. package/dist/data-plane/server/indexing/plugins/thread-gate.d.ts +1 -1
  84. package/dist/data-plane/server/indexing/plugins/thread-gate.d.ts.map +1 -1
  85. package/dist/data-plane/server/indexing/plugins/thread-gate.js.map +1 -1
  86. package/dist/data-plane/server/indexing/plugins/verification.d.ts +1 -1
  87. package/dist/data-plane/server/indexing/plugins/verification.d.ts.map +1 -1
  88. package/dist/data-plane/server/indexing/plugins/verification.js.map +1 -1
  89. package/dist/data-plane/server/indexing/processor.d.ts +1 -1
  90. package/dist/data-plane/server/indexing/processor.d.ts.map +1 -1
  91. package/dist/data-plane/server/indexing/processor.js.map +1 -1
  92. package/dist/data-plane/server/routes/notifs.d.ts.map +1 -1
  93. package/dist/data-plane/server/routes/notifs.js +1 -8
  94. package/dist/data-plane/server/routes/notifs.js.map +1 -1
  95. package/dist/data-plane/server/routes/search.js +2 -2
  96. package/dist/data-plane/server/routes/search.js.map +1 -1
  97. package/dist/data-plane/server/subscription.d.ts +13 -12
  98. package/dist/data-plane/server/subscription.d.ts.map +1 -1
  99. package/dist/data-plane/server/subscription.js +59 -26
  100. package/dist/data-plane/server/subscription.js.map +1 -1
  101. package/dist/feature-gates/index.d.ts +2 -1
  102. package/dist/feature-gates/index.d.ts.map +1 -1
  103. package/dist/feature-gates/index.js +9 -6
  104. package/dist/feature-gates/index.js.map +1 -1
  105. package/dist/feature-gates/metrics.d.ts +3 -3
  106. package/dist/feature-gates/metrics.d.ts.map +1 -1
  107. package/dist/feature-gates/metrics.js +8 -8
  108. package/dist/feature-gates/metrics.js.map +1 -1
  109. package/dist/index.d.ts +1 -0
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js +16 -7
  112. package/dist/index.js.map +1 -1
  113. package/dist/lexicons/app/bsky/notification/defs.defs.d.ts +5 -0
  114. package/dist/lexicons/app/bsky/notification/defs.defs.d.ts.map +1 -1
  115. package/dist/lexicons/app/bsky/notification/defs.defs.js +1 -0
  116. package/dist/lexicons/app/bsky/notification/defs.defs.js.map +1 -1
  117. package/dist/lexicons/chat/bsky/notification/defs.d.ts +2 -0
  118. package/dist/lexicons/chat/bsky/notification/defs.d.ts.map +1 -0
  119. package/dist/lexicons/chat/bsky/notification/defs.defs.d.ts +20 -0
  120. package/dist/lexicons/chat/bsky/notification/defs.defs.d.ts.map +1 -0
  121. package/dist/lexicons/chat/bsky/notification/defs.defs.js +19 -0
  122. package/dist/lexicons/chat/bsky/notification/defs.defs.js.map +1 -0
  123. package/dist/lexicons/chat/bsky/notification/defs.js +5 -0
  124. package/dist/lexicons/chat/bsky/notification/defs.js.map +1 -0
  125. package/dist/lexicons/chat/bsky/notification/getPreferences.d.ts +3 -0
  126. package/dist/lexicons/chat/bsky/notification/getPreferences.d.ts.map +1 -0
  127. package/dist/lexicons/chat/bsky/notification/getPreferences.defs.d.ts +18 -0
  128. package/dist/lexicons/chat/bsky/notification/getPreferences.defs.d.ts.map +1 -0
  129. package/dist/lexicons/chat/bsky/notification/getPreferences.defs.js +16 -0
  130. package/dist/lexicons/chat/bsky/notification/getPreferences.defs.js.map +1 -0
  131. package/dist/lexicons/chat/bsky/notification/getPreferences.js +6 -0
  132. package/dist/lexicons/chat/bsky/notification/getPreferences.js.map +1 -0
  133. package/dist/lexicons/chat/bsky/notification/putPreferences.d.ts +3 -0
  134. package/dist/lexicons/chat/bsky/notification/putPreferences.d.ts.map +1 -0
  135. package/dist/lexicons/chat/bsky/notification/putPreferences.defs.d.ts +27 -0
  136. package/dist/lexicons/chat/bsky/notification/putPreferences.defs.d.ts.map +1 -0
  137. package/dist/lexicons/chat/bsky/notification/putPreferences.defs.js +22 -0
  138. package/dist/lexicons/chat/bsky/notification/putPreferences.defs.js.map +1 -0
  139. package/dist/lexicons/chat/bsky/notification/putPreferences.js +6 -0
  140. package/dist/lexicons/chat/bsky/notification/putPreferences.js.map +1 -0
  141. package/dist/lexicons/chat/bsky/notification.d.ts +4 -0
  142. package/dist/lexicons/chat/bsky/notification.d.ts.map +1 -0
  143. package/dist/lexicons/chat/bsky/notification.js +7 -0
  144. package/dist/lexicons/chat/bsky/notification.js.map +1 -0
  145. package/dist/lexicons/chat/bsky.d.ts +1 -0
  146. package/dist/lexicons/chat/bsky.d.ts.map +1 -1
  147. package/dist/lexicons/chat/bsky.js +1 -0
  148. package/dist/lexicons/chat/bsky.js.map +1 -1
  149. package/dist/lexicons/tools/ozone/report/defs.defs.d.ts +4 -0
  150. package/dist/lexicons/tools/ozone/report/defs.defs.d.ts.map +1 -1
  151. package/dist/lexicons/tools/ozone/report/defs.defs.js +2 -0
  152. package/dist/lexicons/tools/ozone/report/defs.defs.js.map +1 -1
  153. package/dist/lexicons/tools/ozone/report/queryActivities.d.ts +3 -0
  154. package/dist/lexicons/tools/ozone/report/queryActivities.d.ts.map +1 -0
  155. package/dist/lexicons/tools/ozone/report/queryActivities.defs.d.ts +42 -0
  156. package/dist/lexicons/tools/ozone/report/queryActivities.defs.d.ts.map +1 -0
  157. package/dist/lexicons/tools/ozone/report/queryActivities.defs.js +31 -0
  158. package/dist/lexicons/tools/ozone/report/queryActivities.defs.js.map +1 -0
  159. package/dist/lexicons/tools/ozone/report/queryActivities.js +6 -0
  160. package/dist/lexicons/tools/ozone/report/queryActivities.js.map +1 -0
  161. package/dist/lexicons/tools/ozone/report.d.ts +1 -0
  162. package/dist/lexicons/tools/ozone/report.d.ts.map +1 -1
  163. package/dist/lexicons/tools/ozone/report.js +1 -0
  164. package/dist/lexicons/tools/ozone/report.js.map +1 -1
  165. package/dist/proto/bsky_pb.d.ts +47 -53
  166. package/dist/proto/bsky_pb.d.ts.map +1 -1
  167. package/dist/proto/bsky_pb.js +62 -71
  168. package/dist/proto/bsky_pb.js.map +1 -1
  169. package/package.json +10 -10
  170. package/proto/bsky.proto +19 -17
  171. package/src/api/app/bsky/actor/searchActorsTypeahead.ts +5 -3
  172. package/src/api/app/bsky/notification/putPreferencesV2.ts +4 -1
  173. package/src/api/app/bsky/notification/util.ts +7 -11
  174. package/src/api/blob-dispatcher.ts +12 -8
  175. package/src/api/blob-resolver.ts +0 -1
  176. package/src/data-plane/bsync/index.ts +12 -10
  177. package/src/data-plane/server/background.ts +49 -18
  178. package/src/data-plane/server/index.ts +12 -10
  179. package/src/data-plane/server/indexing/index.ts +1 -1
  180. package/src/data-plane/server/indexing/plugins/block.ts +4 -1
  181. package/src/data-plane/server/indexing/plugins/chat-declaration.ts +4 -1
  182. package/src/data-plane/server/indexing/plugins/feed-generator.ts +4 -1
  183. package/src/data-plane/server/indexing/plugins/follow.ts +4 -1
  184. package/src/data-plane/server/indexing/plugins/germ-declaration.ts +4 -1
  185. package/src/data-plane/server/indexing/plugins/labeler.ts +4 -1
  186. package/src/data-plane/server/indexing/plugins/like.ts +4 -1
  187. package/src/data-plane/server/indexing/plugins/list-block.ts +4 -1
  188. package/src/data-plane/server/indexing/plugins/list-item.ts +4 -1
  189. package/src/data-plane/server/indexing/plugins/list.ts +4 -1
  190. package/src/data-plane/server/indexing/plugins/notif-declaration.ts +4 -1
  191. package/src/data-plane/server/indexing/plugins/post-gate.ts +4 -1
  192. package/src/data-plane/server/indexing/plugins/post.ts +4 -1
  193. package/src/data-plane/server/indexing/plugins/profile.ts +4 -1
  194. package/src/data-plane/server/indexing/plugins/repost.ts +4 -1
  195. package/src/data-plane/server/indexing/plugins/starter-pack.ts +4 -1
  196. package/src/data-plane/server/indexing/plugins/status.ts +4 -1
  197. package/src/data-plane/server/indexing/plugins/thread-gate.ts +4 -1
  198. package/src/data-plane/server/indexing/plugins/verification.ts +4 -1
  199. package/src/data-plane/server/indexing/processor.ts +1 -1
  200. package/src/data-plane/server/routes/notifs.ts +0 -14
  201. package/src/data-plane/server/routes/search.ts +2 -2
  202. package/src/data-plane/server/subscription.ts +74 -31
  203. package/src/feature-gates/index.ts +10 -6
  204. package/src/feature-gates/metrics.test.ts +12 -12
  205. package/src/feature-gates/metrics.ts +8 -8
  206. package/src/index.ts +16 -9
  207. package/tests/_util.ts +8 -25
  208. package/tests/admin/admin-auth.test.ts +2 -2
  209. package/tests/admin/moderation.test.ts +1 -1
  210. package/tests/auth.test.ts +4 -6
  211. package/tests/blob-resolver.test.ts +4 -5
  212. package/tests/data-plane/db.test.ts +1 -1
  213. package/tests/data-plane/duplicate-records.test.ts +1 -1
  214. package/tests/data-plane/handle-invalidation.test.ts +2 -2
  215. package/tests/data-plane/indexing.test.ts +24 -21
  216. package/tests/data-plane/subscription.test.ts +1 -1
  217. package/tests/data-plane/thread-mutes.test.ts +2 -2
  218. package/tests/entryway-auth.test.ts +4 -5
  219. package/tests/feed-generation.test.ts +5 -5
  220. package/tests/image/server.test.ts +1 -1
  221. package/tests/label-hydration.test.ts +3 -5
  222. package/tests/postgates.test.ts +3 -6
  223. package/tests/query-labels.test.ts +3 -5
  224. package/tests/redis-cache.test.ts +1 -3
  225. package/tests/server.test.ts +11 -16
  226. package/tests/sitemap.test.ts +3 -4
  227. package/tests/stash.test.ts +12 -8
  228. package/tests/utils.test.ts +3 -13
  229. package/tests/views/account-deactivation.test.ts +3 -5
  230. package/tests/views/actor-likes.test.ts +3 -5
  231. package/tests/views/actor-search.test.ts +6 -7
  232. package/tests/views/age-assurance-v2.test.ts +9 -6
  233. package/tests/views/age-assurance.test.ts +30 -36
  234. package/tests/views/author-feed.test.ts +4 -6
  235. package/tests/views/block-lists.test.ts +3 -5
  236. package/tests/views/blocks.test.ts +3 -5
  237. package/tests/views/bookmarks.test.ts +4 -4
  238. package/tests/views/drafts.test.ts +7 -14
  239. package/tests/views/feed-hidden-replies.test.ts +3 -6
  240. package/tests/views/feed-view-post.test.ts +3 -6
  241. package/tests/views/follows.test.ts +4 -6
  242. package/tests/views/get-config.test.ts +4 -7
  243. package/tests/views/get-suggested-onboarding-users.test.ts +11 -9
  244. package/tests/views/get-suggested-starter-packs.test.ts +11 -9
  245. package/tests/views/get-trends.test.ts +15 -9
  246. package/tests/views/internal-actor.test.ts +3 -6
  247. package/tests/views/known-followers.test.ts +3 -6
  248. package/tests/views/labeler-service.test.ts +3 -5
  249. package/tests/views/labels-needs-review.test.ts +3 -6
  250. package/tests/views/labels-takedown.test.ts +3 -4
  251. package/tests/views/likes.test.ts +4 -6
  252. package/tests/views/list-feed.test.ts +3 -5
  253. package/tests/views/lists.test.ts +3 -5
  254. package/tests/views/mute-lists.test.ts +3 -5
  255. package/tests/views/mutes.test.ts +4 -5
  256. package/tests/views/notifications.test.ts +12 -11
  257. package/tests/views/post-search.test.ts +3 -24
  258. package/tests/views/posts-debug.test.ts +11 -6
  259. package/tests/views/posts.test.ts +3 -4
  260. package/tests/views/profile-debug.test.ts +11 -5
  261. package/tests/views/profile.test.ts +11 -5
  262. package/tests/views/quotes.test.ts +4 -6
  263. package/tests/views/reposts.test.ts +4 -6
  264. package/tests/views/starter-packs.test.ts +3 -6
  265. package/tests/views/suggestions.test.ts +9 -13
  266. package/tests/views/thread-v2.test.ts +3 -5
  267. package/tests/views/thread.test.ts +3 -7
  268. package/tests/views/threadgating.test.ts +3 -5
  269. package/tests/views/timeline.test.ts +4 -5
  270. package/tests/views/verification.test.ts +4 -6
  271. package/tsconfig.build.tsbuildinfo +1 -1
  272. package/vitest.config.ts +1 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @atproto/bsky
2
2
 
3
+ ## 0.0.244
4
+
5
+ ### Patch Changes
6
+
7
+ - [#5112](https://github.com/bluesky-social/atproto/pull/5112) [`3002e9f`](https://github.com/bluesky-social/atproto/commit/3002e9f195df9715395cb72cd3e613f6e5239679) Thanks [@treethought](https://github.com/treethought)! - searchv2: typeahead params envelope, arabic hint, detected langs
8
+
9
+ - [#5116](https://github.com/bluesky-social/atproto/pull/5116) [`39f5c01`](https://github.com/bluesky-social/atproto/commit/39f5c018791ae70391fc86f44be283075dfa206b) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Update undici dependency to v8.5.0
10
+
11
+ - [#5117](https://github.com/bluesky-social/atproto/pull/5117) [`8a4c88b`](https://github.com/bluesky-social/atproto/commit/8a4c88b0f63fb2d82b1391d64c54e0c760fac48b) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Make BackgroundQueue implementation more resilient
12
+
13
+ - [#5117](https://github.com/bluesky-social/atproto/pull/5117) [`8a4c88b`](https://github.com/bluesky-social/atproto/commit/8a4c88b0f63fb2d82b1391d64c54e0c760fac48b) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Make tests less flaky in CI
14
+
15
+ - [#5117](https://github.com/bluesky-social/atproto/pull/5117) [`8a4c88b`](https://github.com/bluesky-social/atproto/commit/8a4c88b0f63fb2d82b1391d64c54e0c760fac48b) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Use http-terminator to close http server
16
+
17
+ - Updated dependencies [[`39f5c01`](https://github.com/bluesky-social/atproto/commit/39f5c018791ae70391fc86f44be283075dfa206b), [`8a4c88b`](https://github.com/bluesky-social/atproto/commit/8a4c88b0f63fb2d82b1391d64c54e0c760fac48b), [`8a4c88b`](https://github.com/bluesky-social/atproto/commit/8a4c88b0f63fb2d82b1391d64c54e0c760fac48b), [`cab3ac3`](https://github.com/bluesky-social/atproto/commit/cab3ac321bf939a4c8ba29aed3f632d8a91790bf)]:
18
+ - @atproto-labs/fetch-node@0.3.2
19
+ - @atproto/sync@0.3.3
20
+ - @atproto/api@0.20.17
21
+
3
22
  ## 0.0.243
4
23
 
5
24
  ### Patch Changes
@@ -59,9 +59,11 @@ const skeletonV2 = async (inputs) => {
59
59
  const { ctx, params } = inputs;
60
60
  const term = params.q ?? params.term ?? '';
61
61
  const res = await ctx.dataplane.searchActorsTypeahead({
62
- viewer: params.hydrateCtx.viewer ?? undefined,
63
- query: term,
64
- limit: params.limit,
62
+ params: {
63
+ query: term,
64
+ viewer: params.hydrateCtx.viewer ?? undefined,
65
+ limit: params.limit,
66
+ },
65
67
  });
66
68
  return {
67
69
  dids: res.actors.map(({ did }) => did),
@@ -1 +1 @@
1
- {"version":3,"file":"searchActorsTypeahead.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/actor/searchActorsTypeahead.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined } from '@atproto/common'\nimport { Client, DidString } from '@atproto/lex'\nimport { Server } from '@atproto/xrpc-server'\nimport { AppContext } from '../../../../context.js'\nimport { DataPlaneClient } from '../../../../data-plane/index.js'\nimport { HydrateCtx, Hydrator } from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n HydrationFnInput,\n PresentationFnInput,\n RulesFnInput,\n SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline.js'\nimport { Views } from '../../../../views/index.js'\nimport { resHeaders, resolveSearchV2Override } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const searchActorsTypeahead = createPipeline(\n skeleton,\n hydration,\n noBlocks,\n presentation,\n )\n server.add(app.bsky.actor.searchActorsTypeahead, {\n auth: ctx.authVerifier.standardOptional,\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 features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({\n viewer,\n req,\n }),\n ),\n })\n const results = await searchActorsTypeahead(\n {\n ...params,\n hydrateCtx,\n isV2Override: resolveSearchV2Override(req, ctx.cfg),\n },\n ctx,\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 term = params.q ?? params.term ?? ''\n\n // @TODO\n // add typeahead option\n // add hits total\n\n if (ctx.searchClient) {\n const { actors } = await ctx.searchClient.call(\n app.bsky.unspecced.searchActorsSkeleton,\n {\n typeahead: true,\n q: term,\n limit: params.limit,\n viewer: params.hydrateCtx.viewer ?? undefined,\n },\n )\n return {\n dids: actors.map(({ did }) => did),\n }\n }\n\n const res = await ctx.dataplane.searchActors({\n term,\n limit: params.limit,\n })\n return {\n dids: res.dids as DidString[],\n }\n}\n\nconst skeletonV2 = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n const { ctx, params } = inputs\n const term = params.q ?? params.term ?? ''\n\n const res = await ctx.dataplane.searchActorsTypeahead({\n viewer: params.hydrateCtx.viewer ?? undefined,\n query: term,\n limit: params.limit,\n })\n return {\n dids: res.actors.map(({ did }) => did as DidString),\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.hydrateProfilesBasic(skeleton.dids, params.hydrateCtx)\n}\n\nconst noBlocks = (inputs: RulesFnInput<Context, Params, Skeleton>) => {\n const { ctx, skeleton, hydration, params } = inputs\n skeleton.dids = skeleton.dids.filter((did) => {\n const actor = hydration.actors?.get(did)\n if (!actor) return false\n // Always display exact matches so that users can find profiles that they have blocked\n const term = (params.q ?? params.term ?? '').toLowerCase()\n const isExactMatch = actor.handle?.toLowerCase() === term\n return isExactMatch || !ctx.views.viewerBlockExists(did, hydration)\n })\n return skeleton\n}\n\nconst presentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, skeleton, hydration } = inputs\n const actors = mapDefined(skeleton.dids, (did) =>\n ctx.views.profileBasic(did, hydration),\n )\n return {\n actors,\n }\n}\n\ntype Context = {\n dataplane: DataPlaneClient\n hydrator: Hydrator\n views: Views\n searchClient?: Client\n}\n\ntype Params = app.bsky.actor.searchActorsTypeahead.$Params & {\n hydrateCtx: HydrateCtx\n isV2Override: boolean\n}\n\ntype Skeleton = {\n dids: DidString[]\n}\n"]}
1
+ {"version":3,"file":"searchActorsTypeahead.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/actor/searchActorsTypeahead.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined } from '@atproto/common'\nimport { Client, DidString } from '@atproto/lex'\nimport { Server } from '@atproto/xrpc-server'\nimport { AppContext } from '../../../../context.js'\nimport { DataPlaneClient } from '../../../../data-plane/index.js'\nimport { HydrateCtx, Hydrator } from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n HydrationFnInput,\n PresentationFnInput,\n RulesFnInput,\n SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline.js'\nimport { Views } from '../../../../views/index.js'\nimport { resHeaders, resolveSearchV2Override } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const searchActorsTypeahead = createPipeline(\n skeleton,\n hydration,\n noBlocks,\n presentation,\n )\n server.add(app.bsky.actor.searchActorsTypeahead, {\n auth: ctx.authVerifier.standardOptional,\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 features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({\n viewer,\n req,\n }),\n ),\n })\n const results = await searchActorsTypeahead(\n {\n ...params,\n hydrateCtx,\n isV2Override: resolveSearchV2Override(req, ctx.cfg),\n },\n ctx,\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 term = params.q ?? params.term ?? ''\n\n // @TODO\n // add typeahead option\n // add hits total\n\n if (ctx.searchClient) {\n const { actors } = await ctx.searchClient.call(\n app.bsky.unspecced.searchActorsSkeleton,\n {\n typeahead: true,\n q: term,\n limit: params.limit,\n viewer: params.hydrateCtx.viewer ?? undefined,\n },\n )\n return {\n dids: actors.map(({ did }) => did),\n }\n }\n\n const res = await ctx.dataplane.searchActors({\n term,\n limit: params.limit,\n })\n return {\n dids: res.dids as DidString[],\n }\n}\n\nconst skeletonV2 = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n const { ctx, params } = inputs\n const term = params.q ?? params.term ?? ''\n\n const res = await ctx.dataplane.searchActorsTypeahead({\n params: {\n query: term,\n viewer: params.hydrateCtx.viewer ?? undefined,\n limit: params.limit,\n },\n })\n return {\n dids: res.actors.map(({ did }) => did as DidString),\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.hydrateProfilesBasic(skeleton.dids, params.hydrateCtx)\n}\n\nconst noBlocks = (inputs: RulesFnInput<Context, Params, Skeleton>) => {\n const { ctx, skeleton, hydration, params } = inputs\n skeleton.dids = skeleton.dids.filter((did) => {\n const actor = hydration.actors?.get(did)\n if (!actor) return false\n // Always display exact matches so that users can find profiles that they have blocked\n const term = (params.q ?? params.term ?? '').toLowerCase()\n const isExactMatch = actor.handle?.toLowerCase() === term\n return isExactMatch || !ctx.views.viewerBlockExists(did, hydration)\n })\n return skeleton\n}\n\nconst presentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, skeleton, hydration } = inputs\n const actors = mapDefined(skeleton.dids, (did) =>\n ctx.views.profileBasic(did, hydration),\n )\n return {\n actors,\n }\n}\n\ntype Context = {\n dataplane: DataPlaneClient\n hydrator: Hydrator\n views: Views\n searchClient?: Client\n}\n\ntype Params = app.bsky.actor.searchActorsTypeahead.$Params & {\n hydrateCtx: HydrateCtx\n isV2Override: boolean\n}\n\ntype Skeleton = {\n dids: DidString[]\n}\n"]}
@@ -2,7 +2,7 @@ import assert from 'node:assert';
2
2
  import { UpstreamFailureError } from '@atproto/xrpc-server';
3
3
  import { app } from '../../../../lexicons/index.js';
4
4
  import { Namespaces } from '../../../../stash.js';
5
- import { protobufToLex } from './util.js';
5
+ import { DEFAULT_CHAT_PREFERENCE, protobufToLex } from './util.js';
6
6
  export default function (server, ctx) {
7
7
  server.add(app.bsky.notification.putPreferencesV2, {
8
8
  auth: ctx.authVerifier.standard,
@@ -38,6 +38,9 @@ const computePreferences = async (ctx, actorDid, input) => {
38
38
  assert(res.preferences.length === 1, `expected exactly one preferences entry, got ${res.preferences.length}`);
39
39
  const currentPreferences = protobufToLex(res.preferences[0]);
40
40
  const preferences = { ...currentPreferences, ...input.body };
41
+ // NOTE: See the deprecation notice on the lexicon. This field returns a static default value and shouldn't be used.
42
+ // Use the chat.bsky.notification.defs#preferences type instead.
43
+ preferences.chat = DEFAULT_CHAT_PREFERENCE;
41
44
  return preferences;
42
45
  };
43
46
  //# sourceMappingURL=putPreferencesV2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"putPreferencesV2.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/notification/putPreferencesV2.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAA;AAEhC,OAAO,EAAU,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAEnE,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AAEnD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAEzC,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE;QACjD,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,QAAQ;QAC/B,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;YACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAA;YACrC,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAA;YAElE,oGAAoG;YACpG,MAAM,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC;gBAC3B,QAAQ;gBACR,SAAS,EAAE,UAAU,CAAC,kCAAkC;gBACxD,GAAG,EAAE,MAAM;gBACX,OAAO,EAAE,WAAW;aACrB,CAAC,CAAA;YAEF,OAAO;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE;oBACJ,WAAW;iBACZ;aACF,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,kBAAkB,GAAG,KAAK,EAC9B,GAAe,EACf,QAAgB,EAChB,KAAoD,EACO,EAAE;IAC7D,IAAI,GAAuC,CAAA;IAC3C,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,0BAA0B,CAAC;YACnD,IAAI,EAAE,CAAC,QAAQ,CAAC;SACjB,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,oBAAoB,CAC5B,6CAA6C,EAC7C,+BAA+B,EAC/B,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAA;IACH,CAAC;IAED,MAAM,CACJ,GAAG,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAC5B,+CAA+C,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,CACxE,CAAA;IAED,MAAM,kBAAkB,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;IAC5D,MAAM,WAAW,GAAG,EAAE,GAAG,kBAAkB,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC5D,OAAO,WAAW,CAAA;AACpB,CAAC,CAAA","sourcesContent":["import assert from 'node:assert'\nimport { Un$Typed } from '@atproto/lex'\nimport { Server, UpstreamFailureError } from '@atproto/xrpc-server'\nimport { AppContext } from '../../../../context.js'\nimport { app } from '../../../../lexicons/index.js'\nimport { GetNotificationPreferencesResponse } from '../../../../proto/bsky_pb.js'\nimport { Namespaces } from '../../../../stash.js'\nimport { protobufToLex } from './util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n server.add(app.bsky.notification.putPreferencesV2, {\n auth: ctx.authVerifier.standard,\n handler: async ({ auth, input }) => {\n const actorDid = auth.credentials.iss\n const preferences = await computePreferences(ctx, actorDid, input)\n\n // Notification preferences are created automatically on the dataplane on signup, so we just update.\n await ctx.stashClient.update({\n actorDid,\n namespace: Namespaces.AppBskyNotificationDefsPreferences,\n key: 'self',\n payload: preferences,\n })\n\n return {\n encoding: 'application/json',\n body: {\n preferences,\n },\n }\n },\n })\n}\n\nconst computePreferences = async (\n ctx: AppContext,\n actorDid: string,\n input: app.bsky.notification.putPreferencesV2.$Input,\n): Promise<Un$Typed<app.bsky.notification.defs.Preferences>> => {\n let res: GetNotificationPreferencesResponse\n try {\n res = await ctx.dataplane.getNotificationPreferences({\n dids: [actorDid],\n })\n } catch (err) {\n throw new UpstreamFailureError(\n 'cannot get current notification preferences',\n 'NotificationPreferencesFailed',\n { cause: err },\n )\n }\n\n assert(\n res.preferences.length === 1,\n `expected exactly one preferences entry, got ${res.preferences.length}`,\n )\n\n const currentPreferences = protobufToLex(res.preferences[0])\n const preferences = { ...currentPreferences, ...input.body }\n return preferences\n}\n"]}
1
+ {"version":3,"file":"putPreferencesV2.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/notification/putPreferencesV2.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAA;AAEhC,OAAO,EAAU,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAEnE,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AAEnD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAElE,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE;QACjD,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,QAAQ;QAC/B,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;YACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAA;YACrC,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAA;YAElE,oGAAoG;YACpG,MAAM,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC;gBAC3B,QAAQ;gBACR,SAAS,EAAE,UAAU,CAAC,kCAAkC;gBACxD,GAAG,EAAE,MAAM;gBACX,OAAO,EAAE,WAAW;aACrB,CAAC,CAAA;YAEF,OAAO;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE;oBACJ,WAAW;iBACZ;aACF,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,kBAAkB,GAAG,KAAK,EAC9B,GAAe,EACf,QAAgB,EAChB,KAAoD,EACO,EAAE;IAC7D,IAAI,GAAuC,CAAA;IAC3C,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,0BAA0B,CAAC;YACnD,IAAI,EAAE,CAAC,QAAQ,CAAC;SACjB,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,oBAAoB,CAC5B,6CAA6C,EAC7C,+BAA+B,EAC/B,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAA;IACH,CAAC;IAED,MAAM,CACJ,GAAG,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAC5B,+CAA+C,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,CACxE,CAAA;IAED,MAAM,kBAAkB,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;IAC5D,MAAM,WAAW,GAAG,EAAE,GAAG,kBAAkB,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC5D,oHAAoH;IACpH,gEAAgE;IAChE,WAAW,CAAC,IAAI,GAAG,uBAAuB,CAAA;IAC1C,OAAO,WAAW,CAAA;AACpB,CAAC,CAAA","sourcesContent":["import assert from 'node:assert'\nimport { Un$Typed } from '@atproto/lex'\nimport { Server, UpstreamFailureError } from '@atproto/xrpc-server'\nimport { AppContext } from '../../../../context.js'\nimport { app } from '../../../../lexicons/index.js'\nimport { GetNotificationPreferencesResponse } from '../../../../proto/bsky_pb.js'\nimport { Namespaces } from '../../../../stash.js'\nimport { DEFAULT_CHAT_PREFERENCE, protobufToLex } from './util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n server.add(app.bsky.notification.putPreferencesV2, {\n auth: ctx.authVerifier.standard,\n handler: async ({ auth, input }) => {\n const actorDid = auth.credentials.iss\n const preferences = await computePreferences(ctx, actorDid, input)\n\n // Notification preferences are created automatically on the dataplane on signup, so we just update.\n await ctx.stashClient.update({\n actorDid,\n namespace: Namespaces.AppBskyNotificationDefsPreferences,\n key: 'self',\n payload: preferences,\n })\n\n return {\n encoding: 'application/json',\n body: {\n preferences,\n },\n }\n },\n })\n}\n\nconst computePreferences = async (\n ctx: AppContext,\n actorDid: string,\n input: app.bsky.notification.putPreferencesV2.$Input,\n): Promise<Un$Typed<app.bsky.notification.defs.Preferences>> => {\n let res: GetNotificationPreferencesResponse\n try {\n res = await ctx.dataplane.getNotificationPreferences({\n dids: [actorDid],\n })\n } catch (err) {\n throw new UpstreamFailureError(\n 'cannot get current notification preferences',\n 'NotificationPreferencesFailed',\n { cause: err },\n )\n }\n\n assert(\n res.preferences.length === 1,\n `expected exactly one preferences entry, got ${res.preferences.length}`,\n )\n\n const currentPreferences = protobufToLex(res.preferences[0])\n const preferences = { ...currentPreferences, ...input.body }\n // NOTE: See the deprecation notice on the lexicon. This field returns a static default value and shouldn't be used.\n // Use the chat.bsky.notification.defs#preferences type instead.\n preferences.chat = DEFAULT_CHAT_PREFERENCE\n return preferences\n}\n"]}
@@ -4,6 +4,7 @@ import { AppPlatform } from '../../../../proto/courier_pb.js';
4
4
  type DeepPartial<T> = T extends object ? {
5
5
  [P in keyof T]?: DeepPartial<T[P]>;
6
6
  } : T;
7
+ export declare const DEFAULT_CHAT_PREFERENCE: app.bsky.notification.defs.ChatPreference;
7
8
  export declare const protobufToLex: (res: DeepPartial<NotificationPreferences>) => app.bsky.notification.defs.Preferences;
8
9
  type LexPlatform = 'ios' | 'android' | 'web';
9
10
  export declare function assertLexPlatform(platform: string): asserts platform is LexPlatform;
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/notification/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAML,uBAAuB,EACxB,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AAE7D,KAAK,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAClC;KACG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACnC,GACD,CAAC,CAAA;AAuFL,eAAO,MAAM,aAAa,QACnB,WAAW,CAAC,uBAAuB,CAAC,KACxC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAgB7B,CAAA;AAED,KAAK,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,CAAA;AAE5C,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,QAAQ,IAAI,WAAW,CAIjC;AAED,eAAO,MAAM,0BAA0B,aAAc,MAAM,KAAG,WAKvC,CAAA"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/notification/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAIL,uBAAuB,EACxB,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AAE7D,KAAK,WAAW,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAClC;KACG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACnC,GACD,CAAC,CAAA;AA0DL,eAAO,MAAM,uBAAuB,EAAE,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,cAI9D,CAAA;AAqBH,eAAO,MAAM,aAAa,QACnB,WAAW,CAAC,uBAAuB,CAAC,KACxC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAkB7B,CAAA;AAED,KAAK,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,CAAA;AAE5C,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,QAAQ,IAAI,WAAW,CAIjC;AAED,eAAO,MAAM,0BAA0B,aAAc,MAAM,KAAG,WAKvC,CAAA"}
@@ -1,4 +1,4 @@
1
- import { ChatNotificationInclude, NotificationInclude, } from '../../../../proto/bsky_pb.js';
1
+ import { NotificationInclude, } from '../../../../proto/bsky_pb.js';
2
2
  import { AppPlatform } from '../../../../proto/courier_pb.js';
3
3
  const ensureChatPreference = (p) => {
4
4
  const includeValues = ['all', 'accepted'];
@@ -42,11 +42,9 @@ const ensurePreferences = (p) => {
42
42
  verified: ensurePreference(p.verified),
43
43
  };
44
44
  };
45
- const protobufChatPreferenceToLex = (p) => {
46
- return {
47
- include: p?.include === ChatNotificationInclude.ACCEPTED ? 'accepted' : 'all',
48
- push: p?.push?.enabled,
49
- };
45
+ export const DEFAULT_CHAT_PREFERENCE = {
46
+ include: 'all',
47
+ push: true,
50
48
  };
51
49
  const protobufFilterablePreferenceToLex = (p) => {
52
50
  return {
@@ -63,7 +61,9 @@ const protobufPreferenceToLex = (p) => {
63
61
  };
64
62
  export const protobufToLex = (res) => {
65
63
  return ensurePreferences({
66
- chat: protobufChatPreferenceToLex(res.chat),
64
+ // NOTE: See the deprecation notice on the lexicon. This field returns a static default value and shouldn't be used.
65
+ // Use the chat.bsky.notification.defs#preferences type instead.
66
+ chat: DEFAULT_CHAT_PREFERENCE,
67
67
  follow: protobufFilterablePreferenceToLex(res.follow),
68
68
  like: protobufFilterablePreferenceToLex(res.like),
69
69
  likeViaRepost: protobufFilterablePreferenceToLex(res.likeViaRepost),
@@ -1 +1 @@
1
- {"version":3,"file":"util.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/notification/util.ts"],"names":[],"mappings":"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","sourcesContent":["import { app } from '../../../../lexicons/index.js'\nimport {\n ChatNotificationInclude,\n ChatNotificationPreference,\n FilterableNotificationPreference,\n NotificationInclude,\n NotificationPreference,\n NotificationPreferences,\n} from '../../../../proto/bsky_pb.js'\nimport { AppPlatform } from '../../../../proto/courier_pb.js'\n\ntype DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n\nconst ensureChatPreference = (\n p?: DeepPartial<app.bsky.notification.defs.ChatPreference>,\n): app.bsky.notification.defs.ChatPreference => {\n const includeValues = ['all', 'accepted']\n return {\n include:\n typeof p?.include === 'string' && includeValues.includes(p.include)\n ? p.include\n : 'all',\n push: p?.push ?? true,\n }\n}\n\nconst ensureFilterablePreference = (\n p?: DeepPartial<app.bsky.notification.defs.FilterablePreference>,\n): app.bsky.notification.defs.FilterablePreference => {\n const includeValues = ['all', 'follows']\n return {\n include:\n typeof p?.include === 'string' && includeValues.includes(p.include)\n ? p.include\n : 'all',\n list: p?.list ?? true,\n push: p?.push ?? true,\n }\n}\n\nconst ensurePreference = (\n p?: DeepPartial<app.bsky.notification.defs.Preference>,\n): app.bsky.notification.defs.Preference => {\n return {\n list: p?.list ?? true,\n push: p?.push ?? true,\n }\n}\n\nconst ensurePreferences = (\n p: DeepPartial<app.bsky.notification.defs.Preferences>,\n): app.bsky.notification.defs.Preferences => {\n return {\n chat: ensureChatPreference(p.chat),\n follow: ensureFilterablePreference(p.follow),\n like: ensureFilterablePreference(p.like),\n likeViaRepost: ensureFilterablePreference(p.likeViaRepost),\n mention: ensureFilterablePreference(p.mention),\n quote: ensureFilterablePreference(p.quote),\n reply: ensureFilterablePreference(p.reply),\n repost: ensureFilterablePreference(p.repost),\n repostViaRepost: ensureFilterablePreference(p.repostViaRepost),\n starterpackJoined: ensurePreference(p.starterpackJoined),\n subscribedPost: ensurePreference(p.subscribedPost),\n unverified: ensurePreference(p.unverified),\n verified: ensurePreference(p.verified),\n }\n}\n\nconst protobufChatPreferenceToLex = (\n p?: DeepPartial<ChatNotificationPreference>,\n): Partial<app.bsky.notification.defs.ChatPreference> => {\n return {\n include:\n p?.include === ChatNotificationInclude.ACCEPTED ? 'accepted' : 'all',\n push: p?.push?.enabled,\n }\n}\n\nconst protobufFilterablePreferenceToLex = (\n p?: DeepPartial<FilterableNotificationPreference>,\n): Partial<app.bsky.notification.defs.FilterablePreference> => {\n return {\n include: p?.include === NotificationInclude.FOLLOWS ? 'follows' : 'all',\n list: p?.list?.enabled,\n push: p?.push?.enabled,\n }\n}\n\nconst protobufPreferenceToLex = (\n p?: DeepPartial<NotificationPreference>,\n): Partial<app.bsky.notification.defs.Preference> => {\n return {\n list: p?.list?.enabled,\n push: p?.push?.enabled,\n }\n}\n\nexport const protobufToLex = (\n res: DeepPartial<NotificationPreferences>,\n): app.bsky.notification.defs.Preferences => {\n return ensurePreferences({\n chat: protobufChatPreferenceToLex(res.chat),\n follow: protobufFilterablePreferenceToLex(res.follow),\n like: protobufFilterablePreferenceToLex(res.like),\n likeViaRepost: protobufFilterablePreferenceToLex(res.likeViaRepost),\n mention: protobufFilterablePreferenceToLex(res.mention),\n quote: protobufFilterablePreferenceToLex(res.quote),\n reply: protobufFilterablePreferenceToLex(res.reply),\n repost: protobufFilterablePreferenceToLex(res.repost),\n repostViaRepost: protobufFilterablePreferenceToLex(res.repostViaRepost),\n starterpackJoined: protobufPreferenceToLex(res.starterpackJoined),\n subscribedPost: protobufPreferenceToLex(res.subscribedPost),\n unverified: protobufPreferenceToLex(res.unverified),\n verified: protobufPreferenceToLex(res.verified),\n })\n}\n\ntype LexPlatform = 'ios' | 'android' | 'web'\n\nexport function assertLexPlatform(\n platform: string,\n): asserts platform is LexPlatform {\n if (platform !== 'ios' && platform !== 'android' && platform !== 'web') {\n throw new Error('Unsupported platform: must be \"ios\", \"android\", or \"web\".')\n }\n}\n\nexport const lexPlatformToProtoPlatform = (platform: string): AppPlatform =>\n platform === 'ios'\n ? AppPlatform.IOS\n : platform === 'android'\n ? AppPlatform.ANDROID\n : AppPlatform.WEB\n"]}
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/notification/util.ts"],"names":[],"mappings":"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","sourcesContent":["import { app } from '../../../../lexicons/index.js'\nimport {\n FilterableNotificationPreference,\n NotificationInclude,\n NotificationPreference,\n NotificationPreferences,\n} from '../../../../proto/bsky_pb.js'\nimport { AppPlatform } from '../../../../proto/courier_pb.js'\n\ntype DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>\n }\n : T\n\nconst ensureChatPreference = (\n p?: DeepPartial<app.bsky.notification.defs.ChatPreference>,\n): app.bsky.notification.defs.ChatPreference => {\n const includeValues = ['all', 'accepted']\n return {\n include:\n typeof p?.include === 'string' && includeValues.includes(p.include)\n ? p.include\n : 'all',\n push: p?.push ?? true,\n }\n}\n\nconst ensureFilterablePreference = (\n p?: DeepPartial<app.bsky.notification.defs.FilterablePreference>,\n): app.bsky.notification.defs.FilterablePreference => {\n const includeValues = ['all', 'follows']\n return {\n include:\n typeof p?.include === 'string' && includeValues.includes(p.include)\n ? p.include\n : 'all',\n list: p?.list ?? true,\n push: p?.push ?? true,\n }\n}\n\nconst ensurePreference = (\n p?: DeepPartial<app.bsky.notification.defs.Preference>,\n): app.bsky.notification.defs.Preference => {\n return {\n list: p?.list ?? true,\n push: p?.push ?? true,\n }\n}\n\nconst ensurePreferences = (\n p: DeepPartial<app.bsky.notification.defs.Preferences>,\n): app.bsky.notification.defs.Preferences => {\n return {\n chat: ensureChatPreference(p.chat),\n follow: ensureFilterablePreference(p.follow),\n like: ensureFilterablePreference(p.like),\n likeViaRepost: ensureFilterablePreference(p.likeViaRepost),\n mention: ensureFilterablePreference(p.mention),\n quote: ensureFilterablePreference(p.quote),\n reply: ensureFilterablePreference(p.reply),\n repost: ensureFilterablePreference(p.repost),\n repostViaRepost: ensureFilterablePreference(p.repostViaRepost),\n starterpackJoined: ensurePreference(p.starterpackJoined),\n subscribedPost: ensurePreference(p.subscribedPost),\n unverified: ensurePreference(p.unverified),\n verified: ensurePreference(p.verified),\n }\n}\n\nexport const DEFAULT_CHAT_PREFERENCE: app.bsky.notification.defs.ChatPreference =\n {\n include: 'all',\n push: true,\n }\n\nconst protobufFilterablePreferenceToLex = (\n p?: DeepPartial<FilterableNotificationPreference>,\n): Partial<app.bsky.notification.defs.FilterablePreference> => {\n return {\n include: p?.include === NotificationInclude.FOLLOWS ? 'follows' : 'all',\n list: p?.list?.enabled,\n push: p?.push?.enabled,\n }\n}\n\nconst protobufPreferenceToLex = (\n p?: DeepPartial<NotificationPreference>,\n): Partial<app.bsky.notification.defs.Preference> => {\n return {\n list: p?.list?.enabled,\n push: p?.push?.enabled,\n }\n}\n\nexport const protobufToLex = (\n res: DeepPartial<NotificationPreferences>,\n): app.bsky.notification.defs.Preferences => {\n return ensurePreferences({\n // NOTE: See the deprecation notice on the lexicon. This field returns a static default value and shouldn't be used.\n // Use the chat.bsky.notification.defs#preferences type instead.\n chat: DEFAULT_CHAT_PREFERENCE,\n follow: protobufFilterablePreferenceToLex(res.follow),\n like: protobufFilterablePreferenceToLex(res.like),\n likeViaRepost: protobufFilterablePreferenceToLex(res.likeViaRepost),\n mention: protobufFilterablePreferenceToLex(res.mention),\n quote: protobufFilterablePreferenceToLex(res.quote),\n reply: protobufFilterablePreferenceToLex(res.reply),\n repost: protobufFilterablePreferenceToLex(res.repost),\n repostViaRepost: protobufFilterablePreferenceToLex(res.repostViaRepost),\n starterpackJoined: protobufPreferenceToLex(res.starterpackJoined),\n subscribedPost: protobufPreferenceToLex(res.subscribedPost),\n unverified: protobufPreferenceToLex(res.unverified),\n verified: protobufPreferenceToLex(res.verified),\n })\n}\n\ntype LexPlatform = 'ios' | 'android' | 'web'\n\nexport function assertLexPlatform(\n platform: string,\n): asserts platform is LexPlatform {\n if (platform !== 'ios' && platform !== 'android' && platform !== 'web') {\n throw new Error('Unsupported platform: must be \"ios\", \"android\", or \"web\".')\n }\n}\n\nexport const lexPlatformToProtoPlatform = (platform: string): AppPlatform =>\n platform === 'ios'\n ? AppPlatform.IOS\n : platform === 'android'\n ? AppPlatform.ANDROID\n : AppPlatform.WEB\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"blob-dispatcher.d.ts","sourceRoot":"","sources":["../../src/api/blob-dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,UAAU,EAAoB,MAAM,QAAQ,CAAA;AAE5D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAG3C,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,YAAY,GAAG,UAAU,CA+BlE"}
1
+ {"version":3,"file":"blob-dispatcher.d.ts","sourceRoot":"","sources":["../../src/api/blob-dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,UAAU,EAAsB,MAAM,QAAQ,CAAA;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAG3C,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,YAAY,GAAG,UAAU,CAmClE"}
@@ -1,4 +1,4 @@
1
- import { Agent, Pool, RetryAgent } from 'undici';
1
+ import { Agent, Pool, interceptors } from 'undici';
2
2
  import { isUnicastIp, unicastLookup } from '@atproto-labs/fetch-node';
3
3
  import { RETRYABLE_HTTP_STATUS_CODES } from '../util/retry.js';
4
4
  export function createBlobDispatcher(cfg) {
@@ -23,12 +23,13 @@ export function createBlobDispatcher(cfg) {
23
23
  lookup: cfg.disableSsrfProtection ? undefined : unicastLookup,
24
24
  },
25
25
  });
26
- return cfg.proxyMaxRetries > 0
27
- ? new RetryAgent(baseDispatcher, {
28
- statusCodes: [...RETRYABLE_HTTP_STATUS_CODES],
29
- methods: ['GET', 'HEAD'],
30
- maxRetries: cfg.proxyMaxRetries,
31
- })
32
- : baseDispatcher;
26
+ return baseDispatcher.compose(interceptors.redirect({
27
+ maxRedirections: 10,
28
+ throwOnMaxRedirect: true,
29
+ }), interceptors.retry({
30
+ statusCodes: [...RETRYABLE_HTTP_STATUS_CODES],
31
+ methods: ['GET', 'HEAD'],
32
+ maxRetries: cfg.proxyMaxRetries,
33
+ }));
33
34
  }
34
35
  //# sourceMappingURL=blob-dispatcher.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"blob-dispatcher.js","sourceRoot":"","sources":["../../src/api/blob-dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAc,IAAI,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAC5D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAErE,OAAO,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAA;AAE9D,MAAM,UAAU,oBAAoB,CAAC,GAAiB;IACpD,MAAM,cAAc,GAAG,IAAI,KAAK,CAAC;QAC/B,OAAO,EAAE,GAAG,CAAC,eAAe,EAAE,uBAAuB;QACrD,cAAc,EAAE,GAAG,CAAC,mBAAmB;QACvC,eAAe,EAAE,GAAG,CAAC,oBAAoB;QACzC,WAAW,EAAE,GAAG,CAAC,gBAAgB;QACjC,OAAO,EAAE,GAAG,CAAC,qBAAqB;YAChC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;gBACf,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAC1B,MAAM,YAAY,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAA;gBAClD,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;oBAC1B,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,GAAG,CAAC,CAAA;gBACrD,CAAC;gBACD,IAAI,WAAW,CAAC,QAAQ,CAAC,KAAK,KAAK,EAAE,CAAC;oBACpC,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;gBAC7D,CAAC;gBACD,OAAO,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;YAC/B,CAAC;QACL,OAAO,EAAE;YACP,MAAM,EAAE,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa;SAC9D;KACF,CAAC,CAAA;IAEF,OAAO,GAAG,CAAC,eAAe,GAAG,CAAC;QAC5B,CAAC,CAAC,IAAI,UAAU,CAAC,cAAc,EAAE;YAC7B,WAAW,EAAE,CAAC,GAAG,2BAA2B,CAAC;YAC7C,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC;YACxB,UAAU,EAAE,GAAG,CAAC,eAAe;SAChC,CAAC;QACJ,CAAC,CAAC,cAAc,CAAA;AACpB,CAAC","sourcesContent":["import { Agent, Dispatcher, Pool, RetryAgent } from 'undici'\nimport { isUnicastIp, unicastLookup } from '@atproto-labs/fetch-node'\nimport { ServerConfig } from '../config.js'\nimport { RETRYABLE_HTTP_STATUS_CODES } from '../util/retry.js'\n\nexport function createBlobDispatcher(cfg: ServerConfig): Dispatcher {\n const baseDispatcher = new Agent({\n allowH2: cfg.proxyAllowHTTP2, // This is experimental\n headersTimeout: cfg.proxyHeadersTimeout,\n maxResponseSize: cfg.proxyMaxResponseSize,\n bodyTimeout: cfg.proxyBodyTimeout,\n factory: cfg.disableSsrfProtection\n ? undefined\n : (origin, opts) => {\n const { protocol, hostname } =\n origin instanceof URL ? origin : new URL(origin)\n if (protocol !== 'https:') {\n throw new Error(`Forbidden protocol \"${protocol}\"`)\n }\n if (isUnicastIp(hostname) === false) {\n throw new Error('Hostname resolved to non-unicast address')\n }\n return new Pool(origin, opts)\n },\n connect: {\n lookup: cfg.disableSsrfProtection ? undefined : unicastLookup,\n },\n })\n\n return cfg.proxyMaxRetries > 0\n ? new RetryAgent(baseDispatcher, {\n statusCodes: [...RETRYABLE_HTTP_STATUS_CODES],\n methods: ['GET', 'HEAD'],\n maxRetries: cfg.proxyMaxRetries,\n })\n : baseDispatcher\n}\n"]}
1
+ {"version":3,"file":"blob-dispatcher.js","sourceRoot":"","sources":["../../src/api/blob-dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAc,IAAI,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAA;AAC9D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAErE,OAAO,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAA;AAE9D,MAAM,UAAU,oBAAoB,CAAC,GAAiB;IACpD,MAAM,cAAc,GAAG,IAAI,KAAK,CAAC;QAC/B,OAAO,EAAE,GAAG,CAAC,eAAe,EAAE,uBAAuB;QACrD,cAAc,EAAE,GAAG,CAAC,mBAAmB;QACvC,eAAe,EAAE,GAAG,CAAC,oBAAoB;QACzC,WAAW,EAAE,GAAG,CAAC,gBAAgB;QACjC,OAAO,EAAE,GAAG,CAAC,qBAAqB;YAChC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;gBACf,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAC1B,MAAM,YAAY,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAA;gBAClD,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;oBAC1B,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,GAAG,CAAC,CAAA;gBACrD,CAAC;gBACD,IAAI,WAAW,CAAC,QAAQ,CAAC,KAAK,KAAK,EAAE,CAAC;oBACpC,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;gBAC7D,CAAC;gBACD,OAAO,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;YAC/B,CAAC;QACL,OAAO,EAAE;YACP,MAAM,EAAE,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa;SAC9D;KACF,CAAC,CAAA;IAEF,OAAO,cAAc,CAAC,OAAO,CAC3B,YAAY,CAAC,QAAQ,CAAC;QACpB,eAAe,EAAE,EAAE;QACnB,kBAAkB,EAAE,IAAI;KACzB,CAAC,EACF,YAAY,CAAC,KAAK,CAAC;QACjB,WAAW,EAAE,CAAC,GAAG,2BAA2B,CAAC;QAC7C,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC;QACxB,UAAU,EAAE,GAAG,CAAC,eAAe;KAChC,CAAC,CACH,CAAA;AACH,CAAC","sourcesContent":["import { Agent, Dispatcher, Pool, interceptors } from 'undici'\nimport { isUnicastIp, unicastLookup } from '@atproto-labs/fetch-node'\nimport { ServerConfig } from '../config.js'\nimport { RETRYABLE_HTTP_STATUS_CODES } from '../util/retry.js'\n\nexport function createBlobDispatcher(cfg: ServerConfig): Dispatcher {\n const baseDispatcher = new Agent({\n allowH2: cfg.proxyAllowHTTP2, // This is experimental\n headersTimeout: cfg.proxyHeadersTimeout,\n maxResponseSize: cfg.proxyMaxResponseSize,\n bodyTimeout: cfg.proxyBodyTimeout,\n factory: cfg.disableSsrfProtection\n ? undefined\n : (origin, opts) => {\n const { protocol, hostname } =\n origin instanceof URL ? origin : new URL(origin)\n if (protocol !== 'https:') {\n throw new Error(`Forbidden protocol \"${protocol}\"`)\n }\n if (isUnicastIp(hostname) === false) {\n throw new Error('Hostname resolved to non-unicast address')\n }\n return new Pool(origin, opts)\n },\n connect: {\n lookup: cfg.disableSsrfProtection ? undefined : unicastLookup,\n },\n })\n\n return baseDispatcher.compose(\n interceptors.redirect({\n maxRedirections: 10,\n throwOnMaxRedirect: true,\n }),\n interceptors.retry({\n statusCodes: [...RETRYABLE_HTTP_STATUS_CODES],\n methods: ['GET', 'HEAD'],\n maxRetries: cfg.proxyMaxRetries,\n }),\n )\n}\n"]}
@@ -16,5 +16,5 @@ export type StreamBlobFactory = (data: Dispatcher.StreamFactoryData, info: {
16
16
  did: AtprotoDid;
17
17
  cid: Cid;
18
18
  }) => Writable;
19
- export declare function streamBlob(ctx: AppContext, options: StreamBlobOptions, factory: StreamBlobFactory): Promise<Dispatcher.StreamData>;
19
+ export declare function streamBlob(ctx: AppContext, options: StreamBlobOptions, factory: StreamBlobFactory): Promise<Dispatcher.StreamData<null>>;
20
20
  //# sourceMappingURL=blob-resolver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"blob-resolver.d.ts","sourceRoot":"","sources":["../../src/api/blob-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,QAAQ,EAAE,MAAM,aAAa,CAAA;AAGzD,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAMnC,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAA;AACvD,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAQlC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAU1C,OAAO,EACL,UAAU,EAGX,MAAM,iBAAiB,CAAA;AAGxB,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAoH5D;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,CAC9B,IAAI,EAAE,UAAU,CAAC,iBAAiB,EAClC,IAAI,EAAE;IACJ,GAAG,EAAE,GAAG,CAAA;IACR,GAAG,EAAE,UAAU,CAAA;IACf,GAAG,EAAE,GAAG,CAAA;CACT,KACE,QAAQ,CAAA;AAEb,wBAAsB,UAAU,CAC9B,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,iBAAiB,kCAiE3B"}
1
+ {"version":3,"file":"blob-resolver.d.ts","sourceRoot":"","sources":["../../src/api/blob-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,QAAQ,EAAE,MAAM,aAAa,CAAA;AAGzD,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAMnC,OAAO,EAAE,UAAU,EAAgB,MAAM,cAAc,CAAA;AACvD,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAA;AAQlC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAU1C,OAAO,EACL,UAAU,EAGX,MAAM,iBAAiB,CAAA;AAGxB,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU,CAoH5D;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,CAC9B,IAAI,EAAE,UAAU,CAAC,iBAAiB,EAClC,IAAI,EAAE;IACJ,GAAG,EAAE,GAAG,CAAA;IACR,GAAG,EAAE,UAAU,CAAA;IACf,GAAG,EAAE,GAAG,CAAA;CACT,KACE,QAAQ,CAAA;AAEb,wBAAsB,UAAU,CAC9B,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE,iBAAiB,wCAgE3B"}
@@ -126,7 +126,6 @@ export async function streamBlob(ctx, options, factory) {
126
126
  path: url.pathname + url.search,
127
127
  headers,
128
128
  signal: options.signal,
129
- maxRedirections: 10,
130
129
  }, (upstream) => {
131
130
  headersReceived = true;
132
131
  if (upstream.statusCode !== 200) {
@@ -1 +1 @@
1
- {"version":3,"file":"blob-resolver.js","sourceRoot":"","sources":["../../src/api/blob-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Duplex, Transform, Writable } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\nimport createError, { isHttpError } from 'http-errors'\nimport { Dispatcher } from 'undici'\nimport {\n VerifyCidError,\n VerifyCidTransform,\n createDecoders,\n} from '@atproto/common'\nimport { AtprotoDid, isAtprotoDid } from '@atproto/did'\nimport { Cid } from '@atproto/lex'\nimport {\n ACCEPT_ENCODING_COMPRESSED,\n ACCEPT_ENCODING_UNCOMPRESSED,\n buildProxiedContentEncoding,\n formatAcceptHeader,\n} from '@atproto-labs/xrpc-utils'\nimport { ServerConfig } from '../config.js'\nimport { AppContext } from '../context.js'\nimport {\n Code,\n DataPlaneClient,\n getServiceEndpoint,\n isDataplaneError,\n unpackIdentityServices,\n} from '../data-plane/index.js'\nimport { parseCid } from '../hydration/util.js'\nimport { httpLogger as log } from '../logger.js'\nimport {\n Middleware,\n proxyResponseHeaders,\n responseSignal,\n} from '../util/http.js'\nimport { BSKY_USER_AGENT } from './util.js'\n\nexport function createMiddleware(ctx: AppContext): Middleware {\n return async (req, res, next) => {\n if (req.method !== 'GET' && req.method !== 'HEAD') return next()\n if (!req.url?.startsWith('/blob/')) return next()\n const { length, 2: didParam, 3: cidParam } = req.url.split('/')\n if (length !== 4 || !didParam || !cidParam) return next()\n\n // @TODO Check sec-fetch-* headers (e.g. to prevent files from being\n // displayed as a web page) ?\n\n try {\n const streamOptions: StreamBlobOptions = {\n did: didParam,\n cid: cidParam,\n signal: responseSignal(res),\n // Because we will be verifying the CID, we need to ensure that the\n // upstream response can be de-compressed. We do this by negotiating the\n // \"accept-encoding\" header based on the downstream client's capabilities.\n acceptEncoding: buildProxiedContentEncoding(\n req.headers['accept-encoding'],\n ctx.cfg.proxyPreferCompressed,\n ),\n }\n\n await streamBlob(ctx, streamOptions, (upstream, { cid, did, url }) => {\n const encoding = upstream.headers['content-encoding']\n const verifier = createCidVerifier(cid, encoding)\n\n const logError = (err: unknown) => {\n log.warn(\n { err, did, cid: cid.toString(), pds: url.origin },\n 'blob resolution failed during transmission',\n )\n }\n\n const onError = (err: unknown) => {\n // No need to pipe the data (verifier) into the response, as it is\n // \"errored\". The response processing will continue in the \"catch\"\n // block below (because streamBlob() will reject the promise in case\n // of \"error\" event on the writable stream returned by the factory).\n clearTimeout(graceTimer)\n logError(err)\n }\n\n // Catch any error that occurs before the timer bellow is triggered.\n // The promise returned by streamBlob() will be rejected as soon as\n // the verifier errors.\n verifier.on('error', onError)\n\n // The way I/O work, it is likely that, in case of small payloads, the\n // full upstream response is already buffered at this point. In order to\n // return a 404 instead of a broken response stream, we allow the event\n // loop to to process any pending I/O events before we start piping the\n // bytes to the response. For larger payloads, the response will look\n // like a 200 with a broken chunked response stream. The only way around\n // that would be to buffer the entire response before piping it to the\n // response, which will hurt latency (need the full payload) and memory\n // usage (either RAM or DISK). Since this is more of an edge case, we\n // allow the broken response stream to be sent.\n const graceTimer = setTimeout(() => {\n verifier.off('error', onError)\n\n // Make sure that the content served from the bsky api domain cannot\n // be used to perform XSS attacks (by serving HTML pages)\n res.setHeader(\n 'Content-Security-Policy',\n `default-src 'none'; sandbox`,\n )\n res.setHeader('X-Content-Type-Options', 'nosniff')\n res.setHeader('X-Frame-Options', 'DENY')\n res.setHeader('X-XSS-Protection', '0')\n\n // @TODO Add a cache-control header ?\n // @TODO Add content-disposition header (to force download) ?\n\n proxyResponseHeaders(upstream, res)\n\n // Force chunked encoding. This is required because the verifier will\n // trigger an error *after* the last chunk has been passed through.\n // Because the number of bytes sent will match the content-length, the\n // HTTP response will be considered \"complete\" by the HTTP server. At\n // this point, only trailers headers could indicate that an error\n // occurred, but that is not the behavior we expect.\n res.removeHeader('content-length')\n\n // From this point on, triggering the next middleware (including any\n // error handler) can be problematic because content-type,\n // content-encoding, etc. headers have already been set. Because of\n // this, we make sure that res.headersSent is set to true, preventing\n // another error handler middleware from being called (from the catch\n // block bellow). Not flushing the headers here would require to\n // revert the headers set from this middleware (which we don't do for\n // now).\n res.flushHeaders()\n\n // Pipe the verifier output into the HTTP response\n void pipeline([verifier, res]).catch(logError)\n }, 10) // 0 works too. Allow for additional data to come in for 10ms.\n\n // Write the upstream response into the verifier.\n return verifier\n })\n } catch (err) {\n if (res.headersSent || res.destroyed) {\n res.destroy()\n } else if (err instanceof VerifyCidError) {\n // @NOTE This only works because of the graceTimer above. It will also\n // only be triggered for small payloads.\n next(createError(404, err.message))\n } else if (isHttpError(err)) {\n next(err)\n } else {\n next(createError(502, 'Upstream Error', { cause: err }))\n }\n }\n }\n}\n\nexport type StreamBlobOptions = {\n cid: string\n did: string\n acceptEncoding?: string\n signal?: AbortSignal\n}\n\nexport type StreamBlobFactory = (\n data: Dispatcher.StreamFactoryData,\n info: {\n url: URL\n did: AtprotoDid\n cid: Cid\n },\n) => Writable\n\nexport async function streamBlob(\n ctx: AppContext,\n options: StreamBlobOptions,\n factory: StreamBlobFactory,\n) {\n const { did, cid } = parseBlobParams(options)\n const url = await getBlobUrl(ctx.dataplane, did, cid)\n\n const headers = getBlobHeaders(ctx.cfg, url)\n\n headers.set(\n 'accept-encoding',\n options.acceptEncoding ||\n formatAcceptHeader(\n ctx.cfg.proxyPreferCompressed\n ? ACCEPT_ENCODING_COMPRESSED\n : ACCEPT_ENCODING_UNCOMPRESSED,\n ),\n )\n\n let headersReceived = false\n\n return ctx.blobDispatcher\n .stream(\n {\n method: 'GET',\n origin: url.origin,\n path: url.pathname + url.search,\n headers,\n signal: options.signal,\n maxRedirections: 10,\n },\n (upstream) => {\n headersReceived = true\n\n if (upstream.statusCode !== 200) {\n log.warn(\n {\n did,\n cid: cid.toString(),\n pds: url.origin,\n status: upstream.statusCode,\n },\n `blob resolution failed upstream`,\n )\n\n throw upstream.statusCode >= 400 && upstream.statusCode < 500\n ? createError(404, 'Blob not found', { cause: upstream }) // 4xx => 404\n : createError(502, 'Upstream Error', { cause: upstream }) // !200 && !4xx => 502\n }\n\n return factory(upstream, { url, did, cid })\n },\n )\n .catch((err) => {\n // Is this a connection error, or a stream error ?\n if (!headersReceived) {\n // connection error, dns error, headers timeout, ...\n log.warn(\n { err, did, cid: cid.toString(), pds: url.origin },\n 'blob resolution failed during connection',\n )\n\n throw createError(502, 'Upstream Error', { cause: err })\n }\n\n throw err\n })\n}\n\nfunction parseBlobParams(params: { cid: string; did: string }) {\n const { cid, did } = params\n if (!isAtprotoDid(did)) throw createError(400, 'Invalid did')\n const cidObj = parseCid(cid)\n if (!cidObj) throw createError(400, 'Invalid cid')\n return { cid: cidObj, did }\n}\n\nasync function getBlobUrl(\n dataplane: DataPlaneClient,\n did: string,\n cid: Cid,\n): Promise<URL> {\n const pds = await getBlobPds(dataplane, did, cid)\n\n const url = new URL(`/xrpc/com.atproto.sync.getBlob`, pds)\n url.searchParams.set('did', did)\n url.searchParams.set('cid', cid.toString())\n\n return url\n}\n\nasync function getBlobPds(\n dataplane: DataPlaneClient,\n did: string,\n cid: Cid,\n): Promise<string> {\n const [identity, { takenDown }] = await Promise.all([\n dataplane.getIdentityByDid({ did }).catch((err) => {\n if (isDataplaneError(err, Code.NotFound)) {\n return undefined\n }\n throw err\n }),\n dataplane.getBlobTakedown({ did, cid: cid.toString() }),\n ])\n\n if (takenDown) {\n throw createError(404, 'Blob not found')\n }\n\n const services = identity && unpackIdentityServices(identity.services)\n const pds =\n services &&\n getServiceEndpoint(services, {\n id: 'atproto_pds',\n type: 'AtprotoPersonalDataServer',\n })\n\n if (!pds) {\n throw createError(404, 'Origin not found')\n }\n\n return pds\n}\n\nfunction getBlobHeaders(\n {\n blobRateLimitBypassKey: bypassKey,\n blobRateLimitBypassHostname: bypassHostname,\n }: ServerConfig,\n url: URL,\n): Map<string, string> {\n const headers = new Map<string, string>()\n\n headers.set('user-agent', BSKY_USER_AGENT)\n\n if (bypassKey && bypassHostname) {\n const matchesUrl = bypassHostname.startsWith('.')\n ? url.hostname.endsWith(bypassHostname)\n : url.hostname === bypassHostname\n\n if (matchesUrl) {\n headers.set('x-ratelimit-bypass', bypassKey)\n }\n }\n\n return headers\n}\n\n/**\n * This function creates a passthrough stream that will decompress (if needed)\n * and verify the CID of the input stream. The output data will be identical to\n * the input data.\n *\n * If you need the un-compressed data, you should use a decompress + verify\n * pipeline instead.\n */\nfunction createCidVerifier(cid: Cid, encoding?: string | string[]): Duplex {\n // If the upstream content is compressed, we do not want to return a\n // de-compressed stream here. Indeed, the \"compression\" middleware will\n // compress the response before it is sent downstream, if it is not already\n // compressed. Because of this, it is preferable to return the content as-is\n // to avoid re-compressing it.\n //\n // We do still want to be able to verify the CID, which requires decompressing\n // the input bytes.\n //\n // To that end, we create a passthrough in order to \"tee\" the stream into two\n // streams: one that will be sent, unaltered, downstream, and a pipeline that\n // will be used to decompress & verify the CID (discarding de-compressed\n // data).\n\n const decoders = createDecoders(encoding)\n const verifier = new VerifyCidTransform(cid)\n\n // Optimization: If the content is not compressed, we don't need to \"tee\" the\n // stream, we can use the verifier as simple passthrough.\n if (!decoders.length) return verifier\n\n const pipelineController = new AbortController()\n const pipelineStreams: Duplex[] = [...decoders, verifier]\n const pipelineInput = pipelineStreams[0]!\n\n // Create a promise that will resolve if, and only if, the decoding and\n // verification succeed.\n const pipelinePromise: Promise<null | Error> = pipeline(pipelineStreams, {\n signal: pipelineController.signal,\n }).then(\n () => null,\n (err) => {\n const error = asError(err)\n\n // the data being processed by the pipeline is invalid (e.g. invalid\n // compressed content, non-matching the CID, ...). If that occurs, we can\n // destroy the passthrough (this allows not to wait for the \"flush\" event\n // to propagate the error).\n passthrough.destroy(error)\n\n return error\n },\n )\n\n // We don't care about the un-compressed data, we only use the verifier to\n // detect any error through the pipelinePromise. We still need to pass the\n // verifier into flowing mode to ensure that the pipelinePromise resolves.\n verifier.resume()\n\n const passthrough = new Transform({\n transform(chunk, encoding, callback) {\n pipelineInput.write(chunk, encoding)\n callback(null, chunk)\n },\n flush(callback) {\n // End the input stream, which will resolve the pipeline promise\n pipelineInput.end()\n // End the pass-through stream according to the result of the pipeline\n pipelinePromise.then(callback)\n },\n destroy(err, callback) {\n pipelineController.abort() // Causes pipeline() to destroy all streams\n callback(err)\n },\n })\n\n return passthrough\n}\n\nfunction asError(err: unknown): Error {\n return err instanceof Error\n ? err\n : new Error('Processing failed', { cause: err })\n}\n"]}
1
+ {"version":3,"file":"blob-resolver.js","sourceRoot":"","sources":["../../src/api/blob-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Duplex, Transform, Writable } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\nimport createError, { isHttpError } from 'http-errors'\nimport { Dispatcher } from 'undici'\nimport {\n VerifyCidError,\n VerifyCidTransform,\n createDecoders,\n} from '@atproto/common'\nimport { AtprotoDid, isAtprotoDid } from '@atproto/did'\nimport { Cid } from '@atproto/lex'\nimport {\n ACCEPT_ENCODING_COMPRESSED,\n ACCEPT_ENCODING_UNCOMPRESSED,\n buildProxiedContentEncoding,\n formatAcceptHeader,\n} from '@atproto-labs/xrpc-utils'\nimport { ServerConfig } from '../config.js'\nimport { AppContext } from '../context.js'\nimport {\n Code,\n DataPlaneClient,\n getServiceEndpoint,\n isDataplaneError,\n unpackIdentityServices,\n} from '../data-plane/index.js'\nimport { parseCid } from '../hydration/util.js'\nimport { httpLogger as log } from '../logger.js'\nimport {\n Middleware,\n proxyResponseHeaders,\n responseSignal,\n} from '../util/http.js'\nimport { BSKY_USER_AGENT } from './util.js'\n\nexport function createMiddleware(ctx: AppContext): Middleware {\n return async (req, res, next) => {\n if (req.method !== 'GET' && req.method !== 'HEAD') return next()\n if (!req.url?.startsWith('/blob/')) return next()\n const { length, 2: didParam, 3: cidParam } = req.url.split('/')\n if (length !== 4 || !didParam || !cidParam) return next()\n\n // @TODO Check sec-fetch-* headers (e.g. to prevent files from being\n // displayed as a web page) ?\n\n try {\n const streamOptions: StreamBlobOptions = {\n did: didParam,\n cid: cidParam,\n signal: responseSignal(res),\n // Because we will be verifying the CID, we need to ensure that the\n // upstream response can be de-compressed. We do this by negotiating the\n // \"accept-encoding\" header based on the downstream client's capabilities.\n acceptEncoding: buildProxiedContentEncoding(\n req.headers['accept-encoding'],\n ctx.cfg.proxyPreferCompressed,\n ),\n }\n\n await streamBlob(ctx, streamOptions, (upstream, { cid, did, url }) => {\n const encoding = upstream.headers['content-encoding']\n const verifier = createCidVerifier(cid, encoding)\n\n const logError = (err: unknown) => {\n log.warn(\n { err, did, cid: cid.toString(), pds: url.origin },\n 'blob resolution failed during transmission',\n )\n }\n\n const onError = (err: unknown) => {\n // No need to pipe the data (verifier) into the response, as it is\n // \"errored\". The response processing will continue in the \"catch\"\n // block below (because streamBlob() will reject the promise in case\n // of \"error\" event on the writable stream returned by the factory).\n clearTimeout(graceTimer)\n logError(err)\n }\n\n // Catch any error that occurs before the timer bellow is triggered.\n // The promise returned by streamBlob() will be rejected as soon as\n // the verifier errors.\n verifier.on('error', onError)\n\n // The way I/O work, it is likely that, in case of small payloads, the\n // full upstream response is already buffered at this point. In order to\n // return a 404 instead of a broken response stream, we allow the event\n // loop to to process any pending I/O events before we start piping the\n // bytes to the response. For larger payloads, the response will look\n // like a 200 with a broken chunked response stream. The only way around\n // that would be to buffer the entire response before piping it to the\n // response, which will hurt latency (need the full payload) and memory\n // usage (either RAM or DISK). Since this is more of an edge case, we\n // allow the broken response stream to be sent.\n const graceTimer = setTimeout(() => {\n verifier.off('error', onError)\n\n // Make sure that the content served from the bsky api domain cannot\n // be used to perform XSS attacks (by serving HTML pages)\n res.setHeader(\n 'Content-Security-Policy',\n `default-src 'none'; sandbox`,\n )\n res.setHeader('X-Content-Type-Options', 'nosniff')\n res.setHeader('X-Frame-Options', 'DENY')\n res.setHeader('X-XSS-Protection', '0')\n\n // @TODO Add a cache-control header ?\n // @TODO Add content-disposition header (to force download) ?\n\n proxyResponseHeaders(upstream, res)\n\n // Force chunked encoding. This is required because the verifier will\n // trigger an error *after* the last chunk has been passed through.\n // Because the number of bytes sent will match the content-length, the\n // HTTP response will be considered \"complete\" by the HTTP server. At\n // this point, only trailers headers could indicate that an error\n // occurred, but that is not the behavior we expect.\n res.removeHeader('content-length')\n\n // From this point on, triggering the next middleware (including any\n // error handler) can be problematic because content-type,\n // content-encoding, etc. headers have already been set. Because of\n // this, we make sure that res.headersSent is set to true, preventing\n // another error handler middleware from being called (from the catch\n // block bellow). Not flushing the headers here would require to\n // revert the headers set from this middleware (which we don't do for\n // now).\n res.flushHeaders()\n\n // Pipe the verifier output into the HTTP response\n void pipeline([verifier, res]).catch(logError)\n }, 10) // 0 works too. Allow for additional data to come in for 10ms.\n\n // Write the upstream response into the verifier.\n return verifier\n })\n } catch (err) {\n if (res.headersSent || res.destroyed) {\n res.destroy()\n } else if (err instanceof VerifyCidError) {\n // @NOTE This only works because of the graceTimer above. It will also\n // only be triggered for small payloads.\n next(createError(404, err.message))\n } else if (isHttpError(err)) {\n next(err)\n } else {\n next(createError(502, 'Upstream Error', { cause: err }))\n }\n }\n }\n}\n\nexport type StreamBlobOptions = {\n cid: string\n did: string\n acceptEncoding?: string\n signal?: AbortSignal\n}\n\nexport type StreamBlobFactory = (\n data: Dispatcher.StreamFactoryData,\n info: {\n url: URL\n did: AtprotoDid\n cid: Cid\n },\n) => Writable\n\nexport async function streamBlob(\n ctx: AppContext,\n options: StreamBlobOptions,\n factory: StreamBlobFactory,\n) {\n const { did, cid } = parseBlobParams(options)\n const url = await getBlobUrl(ctx.dataplane, did, cid)\n\n const headers = getBlobHeaders(ctx.cfg, url)\n\n headers.set(\n 'accept-encoding',\n options.acceptEncoding ||\n formatAcceptHeader(\n ctx.cfg.proxyPreferCompressed\n ? ACCEPT_ENCODING_COMPRESSED\n : ACCEPT_ENCODING_UNCOMPRESSED,\n ),\n )\n\n let headersReceived = false\n\n return ctx.blobDispatcher\n .stream(\n {\n method: 'GET',\n origin: url.origin,\n path: url.pathname + url.search,\n headers,\n signal: options.signal,\n },\n (upstream) => {\n headersReceived = true\n\n if (upstream.statusCode !== 200) {\n log.warn(\n {\n did,\n cid: cid.toString(),\n pds: url.origin,\n status: upstream.statusCode,\n },\n `blob resolution failed upstream`,\n )\n\n throw upstream.statusCode >= 400 && upstream.statusCode < 500\n ? createError(404, 'Blob not found', { cause: upstream }) // 4xx => 404\n : createError(502, 'Upstream Error', { cause: upstream }) // !200 && !4xx => 502\n }\n\n return factory(upstream, { url, did, cid })\n },\n )\n .catch((err) => {\n // Is this a connection error, or a stream error ?\n if (!headersReceived) {\n // connection error, dns error, headers timeout, ...\n log.warn(\n { err, did, cid: cid.toString(), pds: url.origin },\n 'blob resolution failed during connection',\n )\n\n throw createError(502, 'Upstream Error', { cause: err })\n }\n\n throw err\n })\n}\n\nfunction parseBlobParams(params: { cid: string; did: string }) {\n const { cid, did } = params\n if (!isAtprotoDid(did)) throw createError(400, 'Invalid did')\n const cidObj = parseCid(cid)\n if (!cidObj) throw createError(400, 'Invalid cid')\n return { cid: cidObj, did }\n}\n\nasync function getBlobUrl(\n dataplane: DataPlaneClient,\n did: string,\n cid: Cid,\n): Promise<URL> {\n const pds = await getBlobPds(dataplane, did, cid)\n\n const url = new URL(`/xrpc/com.atproto.sync.getBlob`, pds)\n url.searchParams.set('did', did)\n url.searchParams.set('cid', cid.toString())\n\n return url\n}\n\nasync function getBlobPds(\n dataplane: DataPlaneClient,\n did: string,\n cid: Cid,\n): Promise<string> {\n const [identity, { takenDown }] = await Promise.all([\n dataplane.getIdentityByDid({ did }).catch((err) => {\n if (isDataplaneError(err, Code.NotFound)) {\n return undefined\n }\n throw err\n }),\n dataplane.getBlobTakedown({ did, cid: cid.toString() }),\n ])\n\n if (takenDown) {\n throw createError(404, 'Blob not found')\n }\n\n const services = identity && unpackIdentityServices(identity.services)\n const pds =\n services &&\n getServiceEndpoint(services, {\n id: 'atproto_pds',\n type: 'AtprotoPersonalDataServer',\n })\n\n if (!pds) {\n throw createError(404, 'Origin not found')\n }\n\n return pds\n}\n\nfunction getBlobHeaders(\n {\n blobRateLimitBypassKey: bypassKey,\n blobRateLimitBypassHostname: bypassHostname,\n }: ServerConfig,\n url: URL,\n): Map<string, string> {\n const headers = new Map<string, string>()\n\n headers.set('user-agent', BSKY_USER_AGENT)\n\n if (bypassKey && bypassHostname) {\n const matchesUrl = bypassHostname.startsWith('.')\n ? url.hostname.endsWith(bypassHostname)\n : url.hostname === bypassHostname\n\n if (matchesUrl) {\n headers.set('x-ratelimit-bypass', bypassKey)\n }\n }\n\n return headers\n}\n\n/**\n * This function creates a passthrough stream that will decompress (if needed)\n * and verify the CID of the input stream. The output data will be identical to\n * the input data.\n *\n * If you need the un-compressed data, you should use a decompress + verify\n * pipeline instead.\n */\nfunction createCidVerifier(cid: Cid, encoding?: string | string[]): Duplex {\n // If the upstream content is compressed, we do not want to return a\n // de-compressed stream here. Indeed, the \"compression\" middleware will\n // compress the response before it is sent downstream, if it is not already\n // compressed. Because of this, it is preferable to return the content as-is\n // to avoid re-compressing it.\n //\n // We do still want to be able to verify the CID, which requires decompressing\n // the input bytes.\n //\n // To that end, we create a passthrough in order to \"tee\" the stream into two\n // streams: one that will be sent, unaltered, downstream, and a pipeline that\n // will be used to decompress & verify the CID (discarding de-compressed\n // data).\n\n const decoders = createDecoders(encoding)\n const verifier = new VerifyCidTransform(cid)\n\n // Optimization: If the content is not compressed, we don't need to \"tee\" the\n // stream, we can use the verifier as simple passthrough.\n if (!decoders.length) return verifier\n\n const pipelineController = new AbortController()\n const pipelineStreams: Duplex[] = [...decoders, verifier]\n const pipelineInput = pipelineStreams[0]!\n\n // Create a promise that will resolve if, and only if, the decoding and\n // verification succeed.\n const pipelinePromise: Promise<null | Error> = pipeline(pipelineStreams, {\n signal: pipelineController.signal,\n }).then(\n () => null,\n (err) => {\n const error = asError(err)\n\n // the data being processed by the pipeline is invalid (e.g. invalid\n // compressed content, non-matching the CID, ...). If that occurs, we can\n // destroy the passthrough (this allows not to wait for the \"flush\" event\n // to propagate the error).\n passthrough.destroy(error)\n\n return error\n },\n )\n\n // We don't care about the un-compressed data, we only use the verifier to\n // detect any error through the pipelinePromise. We still need to pass the\n // verifier into flowing mode to ensure that the pipelinePromise resolves.\n verifier.resume()\n\n const passthrough = new Transform({\n transform(chunk, encoding, callback) {\n pipelineInput.write(chunk, encoding)\n callback(null, chunk)\n },\n flush(callback) {\n // End the input stream, which will resolve the pipeline promise\n pipelineInput.end()\n // End the pass-through stream according to the result of the pipeline\n pipelinePromise.then(callback)\n },\n destroy(err, callback) {\n pipelineController.abort() // Causes pipeline() to destroy all streams\n callback(err)\n },\n })\n\n return passthrough\n}\n\nfunction asError(err: unknown): Error {\n return err instanceof Error\n ? err\n : new Error('Processing failed', { cause: err })\n}\n"]}
@@ -2,8 +2,10 @@ import http from 'node:http';
2
2
  import { Database } from '../server/db/index.js';
3
3
  export declare class MockBsync {
4
4
  server: http.Server;
5
+ private terminator;
5
6
  constructor(server: http.Server);
6
7
  static create(db: Database, port: number): Promise<MockBsync>;
7
8
  destroy(): Promise<void>;
9
+ [Symbol.asyncDispose](): Promise<void>;
8
10
  }
9
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/data-plane/bsync/index.ts"],"names":[],"mappings":"AAEA,OAAO,IAAI,MAAM,WAAW,CAAA;AAgB5B,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAGhD,qBAAa,SAAS;IACD,MAAM,EAAE,IAAI,CAAC,MAAM;IAAtC,YAAmB,MAAM,EAAE,IAAI,CAAC,MAAM,EAAI;IAE1C,OAAa,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,sBAO7C;IAEK,OAAO,kBAUZ;CACF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/data-plane/bsync/index.ts"],"names":[],"mappings":"AAEA,OAAO,IAAI,MAAM,WAAW,CAAA;AAkB5B,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAGhD,qBAAa,SAAS;IAGD,MAAM,EAAE,IAAI,CAAC,MAAM;IAFtC,OAAO,CAAC,UAAU,CAA+B;IAEjD,YAAmB,MAAM,EAAE,IAAI,CAAC,MAAM,EAErC;IAED,OAAa,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,sBAO7C;IAEK,OAAO,kBAEZ;IAEK,CAAC,MAAM,CAAC,YAAY,CAAC,kBAE1B;CACF"}
@@ -2,6 +2,8 @@ import assert from 'node:assert';
2
2
  import events from 'node:events';
3
3
  import { expressConnectMiddleware } from '@connectrpc/connect-express';
4
4
  import express from 'express';
5
+ // eslint-disable-next-line import/default
6
+ import httpTerminator from 'http-terminator';
5
7
  import { TID } from '@atproto/common';
6
8
  import { lexParse } from '@atproto/lex';
7
9
  import { AtUri } from '@atproto/syntax';
@@ -14,6 +16,7 @@ import { countAll, excluded } from '../server/db/util.js';
14
16
  export class MockBsync {
15
17
  constructor(server) {
16
18
  this.server = server;
19
+ this.terminator = httpTerminator.createHttpTerminator({ server });
17
20
  }
18
21
  static async create(db, port) {
19
22
  const app = express();
@@ -24,16 +27,10 @@ export class MockBsync {
24
27
  return new MockBsync(server);
25
28
  }
26
29
  async destroy() {
27
- return new Promise((resolve, reject) => {
28
- this.server.close((err) => {
29
- if (err) {
30
- reject(err);
31
- }
32
- else {
33
- resolve();
34
- }
35
- });
36
- });
30
+ await this.terminator.terminate();
31
+ }
32
+ async [Symbol.asyncDispose]() {
33
+ await this.destroy();
37
34
  }
38
35
  }
39
36
  const createRoutes = (db) => (router) => router.service(Service, {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/data-plane/bsync/index.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from 'node:assert'\nimport events from 'node:events'\nimport http from 'node:http'\nimport { ConnectRouter } from '@connectrpc/connect'\nimport { expressConnectMiddleware } from '@connectrpc/connect-express'\nimport express from 'express'\nimport { TID } from '@atproto/common'\nimport { lexParse } from '@atproto/lex'\nimport { AtUri } from '@atproto/syntax'\nimport { app } from '../../lexicons/index.js'\nimport { httpLogger } from '../../logger.js'\nimport { Service } from '../../proto/bsync_connect.js'\nimport {\n Method,\n MuteOperation_Type,\n PutOperationRequest,\n} from '../../proto/bsync_pb.js'\nimport { Namespaces } from '../../stash.js'\nimport { Database } from '../server/db/index.js'\nimport { countAll, excluded } from '../server/db/util.js'\n\nexport class MockBsync {\n constructor(public server: http.Server) {}\n\n static async create(db: Database, port: number) {\n const app = express()\n const routes = createRoutes(db)\n app.use(expressConnectMiddleware({ routes }))\n const server = app.listen(port)\n await events.once(server, 'listening')\n return new MockBsync(server)\n }\n\n async destroy() {\n return new Promise<void>((resolve, reject) => {\n this.server.close((err) => {\n if (err) {\n reject(err)\n } else {\n resolve()\n }\n })\n })\n }\n}\n\nconst createRoutes = (db: Database) => (router: ConnectRouter) =>\n router.service(Service, {\n async addMuteOperation(req) {\n const { type, actorDid, subject } = req\n if (type === MuteOperation_Type.ADD) {\n if (subject.startsWith('did:')) {\n assert(actorDid !== subject, 'cannot mute yourself') // @TODO pass message through in http error\n await db.db\n .insertInto('mute')\n .values({\n mutedByDid: actorDid,\n subjectDid: subject,\n createdAt: new Date().toISOString(),\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n } else {\n const uri = new AtUri(subject)\n if (uri.collection === app.bsky.graph.list.$type) {\n await db.db\n .insertInto('list_mute')\n .values({\n mutedByDid: actorDid,\n listUri: subject,\n createdAt: new Date().toISOString(),\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n } else {\n await db.db\n .insertInto('thread_mute')\n .values({\n mutedByDid: actorDid,\n rootUri: subject,\n createdAt: new Date().toISOString(),\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n }\n }\n } else if (type === MuteOperation_Type.REMOVE) {\n if (subject.startsWith('did:')) {\n await db.db\n .deleteFrom('mute')\n .where('mutedByDid', '=', actorDid)\n .where('subjectDid', '=', subject)\n .execute()\n } else {\n const uri = new AtUri(subject)\n if (uri.collection === app.bsky.graph.list.$type) {\n await db.db\n .deleteFrom('list_mute')\n .where('mutedByDid', '=', actorDid)\n .where('listUri', '=', subject)\n .execute()\n } else {\n await db.db\n .deleteFrom('thread_mute')\n .where('mutedByDid', '=', actorDid)\n .where('rootUri', '=', subject)\n .execute()\n }\n }\n } else if (type === MuteOperation_Type.CLEAR) {\n await db.db\n .deleteFrom('mute')\n .where('mutedByDid', '=', actorDid)\n .execute()\n await db.db\n .deleteFrom('list_mute')\n .where('mutedByDid', '=', actorDid)\n .execute()\n }\n\n return {}\n },\n\n async scanMuteOperations() {\n throw new Error('not implemented')\n },\n\n async addNotifOperation(req) {\n const { actorDid, priority } = req\n if (priority !== undefined) {\n await db.db\n .insertInto('actor_state')\n .values({\n did: actorDid,\n priorityNotifs: priority,\n lastSeenNotifs: new Date().toISOString(),\n })\n .onConflict((oc) =>\n oc.column('did').doUpdateSet({ priorityNotifs: priority }),\n )\n .execute()\n }\n return {}\n },\n\n async scanNotifOperations() {\n throw new Error('not implemented')\n },\n\n async putOperation(req) {\n const { actorDid, namespace, key, method, payload } = req\n assert(\n method === Method.CREATE ||\n method === Method.UPDATE ||\n method === Method.DELETE,\n `Unsupported method: ${method}`,\n )\n\n const now = new Date().toISOString()\n\n // Index all items into private_data.\n await handleGenericOperation(db, req, now)\n\n // Maintain bespoke indexes for certain namespaces.\n try {\n if (\n namespace ===\n Namespaces.AppBskyNotificationDefsSubjectActivitySubscription.$type\n ) {\n await handleSubjectActivitySubscriptionOperation(db, req, now)\n } else if (\n namespace === Namespaces.AppBskyUnspeccedDefsAgeAssuranceEvent.$type\n ) {\n await handleAgeAssuranceEventOperation(db, req, now)\n } else if (\n namespace === Namespaces.AppBskyAgeassuranceDefsEvent.$type\n ) {\n await handleAgeAssuranceV2EventOperation(db, req, now)\n } else if (namespace === Namespaces.AppBskyBookmarkDefsBookmark.$type) {\n await handleBookmarkOperation(db, req, now)\n } else if (namespace === Namespaces.AppBskyDraftDefsDraftWithId.$type) {\n await handleDraftOperation(db, req, now)\n }\n } catch (err) {\n httpLogger.warn({ err, namespace }, 'mock bsync put operation failed')\n }\n\n return {\n operation: {\n id: TID.nextStr(),\n actorDid,\n namespace,\n key,\n method,\n payload,\n },\n }\n },\n\n async scanOperations() {\n throw new Error('not implemented')\n },\n\n async ping() {\n return {}\n },\n })\n\n// upsert into or remove from private_data\nconst handleGenericOperation = async (\n db: Database,\n req: PutOperationRequest,\n now: string,\n) => {\n const { actorDid, namespace, key, method, payload } = req\n if (method === Method.CREATE || method === Method.UPDATE) {\n await db.db\n .insertInto('private_data')\n .values({\n actorDid,\n namespace,\n key,\n payload: Buffer.from(payload).toString('utf8'),\n indexedAt: now,\n updatedAt: now,\n })\n .onConflict((oc) =>\n oc.columns(['actorDid', 'namespace', 'key']).doUpdateSet({\n payload: excluded(db.db, 'payload'),\n updatedAt: excluded(db.db, 'updatedAt'),\n }),\n )\n .execute()\n } else if (method === Method.DELETE) {\n await db.db\n .deleteFrom('private_data')\n .where('actorDid', '=', actorDid)\n .where('namespace', '=', namespace)\n .where('key', '=', key)\n .execute()\n } else {\n assert.fail(`unexpected method ${method}`)\n }\n}\n\nconst handleSubjectActivitySubscriptionOperation = async (\n db: Database,\n req: PutOperationRequest,\n now: string,\n) => {\n const { actorDid, key, method, payload } = req\n\n if (method === Method.DELETE) {\n return db.db\n .deleteFrom('activity_subscription')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .execute()\n }\n\n const json = Buffer.from(payload).toString('utf8')\n const parsed =\n lexParse<app.bsky.notification.defs.SubjectActivitySubscription>(json)\n const {\n subject,\n activitySubscription: { post, reply },\n } = parsed\n\n if (method === Method.CREATE) {\n return db.db\n .insertInto('activity_subscription')\n .values({\n creator: actorDid,\n subjectDid: subject,\n key,\n indexedAt: now,\n post,\n reply,\n })\n .execute()\n }\n\n return db.db\n .updateTable('activity_subscription')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .set({\n indexedAt: now,\n post,\n reply,\n })\n .execute()\n}\n\nconst handleAgeAssuranceEventOperation = async (\n db: Database,\n req: PutOperationRequest,\n _now: string,\n) => {\n const { actorDid, method, payload } = req\n if (method !== Method.CREATE) return\n\n const parsed = lexParse<app.bsky.unspecced.defs.AgeAssuranceEvent>(\n Buffer.from(payload).toString('utf8'),\n )\n\n const { status, createdAt } = parsed\n\n const update = {\n ageAssuranceStatus: status,\n ageAssuranceLastInitiatedAt: status === 'pending' ? createdAt : undefined,\n }\n\n return db.db\n .updateTable('actor')\n .set(update)\n .where('did', '=', actorDid)\n .execute()\n}\n\nconst handleAgeAssuranceV2EventOperation = async (\n db: Database,\n req: PutOperationRequest,\n _now: string,\n) => {\n const { actorDid, method, payload } = req\n if (method !== Method.CREATE) return\n\n const parsed = lexParse<app.bsky.ageassurance.defs.Event>(\n Buffer.from(payload).toString('utf8'),\n )\n\n const { status, createdAt, access, countryCode, regionCode } = parsed\n\n const update = {\n ageAssuranceStatus: status,\n ageAssuranceLastInitiatedAt: status === 'pending' ? createdAt : undefined,\n ageAssuranceAccess: access,\n ageAssuranceCountryCode: countryCode,\n ageAssuranceRegionCode: regionCode,\n }\n\n return db.db\n .updateTable('actor')\n .set(update)\n .where('did', '=', actorDid)\n .execute()\n}\n\nconst handleBookmarkOperation = async (\n db: Database,\n req: PutOperationRequest,\n now: string,\n) => {\n const { actorDid, key, method, payload } = req\n\n const updateAgg = (uri: string, dbTxn: Database) => {\n return dbTxn.db\n .insertInto('post_agg')\n .values({\n uri,\n bookmarkCount: dbTxn.db\n .selectFrom('bookmark')\n .where('bookmark.subjectUri', '=', uri)\n .select(countAll.as('count')),\n })\n .onConflict((oc) =>\n oc\n .column('uri')\n .doUpdateSet({ bookmarkCount: excluded(dbTxn.db, 'bookmarkCount') }),\n )\n .execute()\n }\n\n if (method === Method.CREATE) {\n const parsed = lexParse<app.bsky.bookmark.defs.Bookmark>(\n Buffer.from(payload).toString('utf8'),\n )\n const {\n subject: { uri, cid },\n } = parsed\n\n await db.transaction(async (dbTxn) => {\n await dbTxn.db\n .insertInto('bookmark')\n .values({\n creator: actorDid,\n key,\n indexedAt: now,\n subjectUri: uri,\n subjectCid: cid,\n })\n .execute()\n\n await updateAgg(uri, dbTxn)\n })\n }\n\n if (method === Method.DELETE) {\n await db.transaction(async (dbTxn) => {\n const bookmark = await dbTxn.db\n .selectFrom('bookmark')\n .selectAll()\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .executeTakeFirst()\n\n if (bookmark) {\n await dbTxn.db\n .deleteFrom('bookmark')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .execute()\n\n await updateAgg(bookmark.subjectUri, dbTxn)\n }\n })\n }\n}\n\nconst handleDraftOperation = async (\n db: Database,\n req: PutOperationRequest,\n now: string,\n) => {\n const { actorDid, key, method, payload } = req\n\n if (method === Method.CREATE) {\n const payloadString = Buffer.from(payload).toString('utf8')\n\n await db.db\n .insertInto('draft')\n .values({\n creator: actorDid,\n key,\n createdAt: now,\n updatedAt: now,\n payload: payloadString,\n })\n .execute()\n }\n\n if (method === Method.UPDATE) {\n const payloadString = Buffer.from(payload).toString('utf8')\n\n await db.db\n .updateTable('draft')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .set({\n updatedAt: now,\n payload: payloadString,\n })\n .execute()\n }\n\n if (method === Method.DELETE) {\n await db.db\n .deleteFrom('draft')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .execute()\n }\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/data-plane/bsync/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAA;AAChC,OAAO,MAAM,MAAM,aAAa,CAAA;AAGhC,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAA;AACtE,OAAO,OAAO,MAAM,SAAS,CAAA;AAC7B,0CAA0C;AAC1C,OAAO,cAAc,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAA;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AACvC,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA;AACtD,OAAO,EACL,MAAM,EACN,kBAAkB,GAEnB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAE3C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAEzD,MAAM,OAAO,SAAS;IAGpB,YAAmB,MAAmB;sBAAnB,MAAM;QACvB,IAAI,CAAC,UAAU,GAAG,cAAc,CAAC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;IACnE,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAY,EAAE,IAAY;QAC5C,MAAM,GAAG,GAAG,OAAO,EAAE,CAAA;QACrB,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,CAAC,CAAA;QAC/B,GAAG,CAAC,GAAG,CAAC,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;QAC7C,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAC/B,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;QACtC,OAAO,IAAI,SAAS,CAAC,MAAM,CAAC,CAAA;IAC9B,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,CAAA;IACnC,CAAC;IAED,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;QACzB,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;IACtB,CAAC;CACF;AAED,MAAM,YAAY,GAAG,CAAC,EAAY,EAAE,EAAE,CAAC,CAAC,MAAqB,EAAE,EAAE,CAC/D,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE;IACtB,KAAK,CAAC,gBAAgB,CAAC,GAAG;QACxB,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,GAAG,CAAA;QACvC,IAAI,IAAI,KAAK,kBAAkB,CAAC,GAAG,EAAE,CAAC;YACpC,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC/B,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,sBAAsB,CAAC,CAAA,CAAC,2CAA2C;gBAChG,MAAM,EAAE,CAAC,EAAE;qBACR,UAAU,CAAC,MAAM,CAAC;qBAClB,MAAM,CAAC;oBACN,UAAU,EAAE,QAAQ;oBACpB,UAAU,EAAE,OAAO;oBACnB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC;qBACD,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC;qBAClC,OAAO,EAAE,CAAA;YACd,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;gBAC9B,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;oBACjD,MAAM,EAAE,CAAC,EAAE;yBACR,UAAU,CAAC,WAAW,CAAC;yBACvB,MAAM,CAAC;wBACN,UAAU,EAAE,QAAQ;wBACpB,OAAO,EAAE,OAAO;wBAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;qBACpC,CAAC;yBACD,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC;yBAClC,OAAO,EAAE,CAAA;gBACd,CAAC;qBAAM,CAAC;oBACN,MAAM,EAAE,CAAC,EAAE;yBACR,UAAU,CAAC,aAAa,CAAC;yBACzB,MAAM,CAAC;wBACN,UAAU,EAAE,QAAQ;wBACpB,OAAO,EAAE,OAAO;wBAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;qBACpC,CAAC;yBACD,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC;yBAClC,OAAO,EAAE,CAAA;gBACd,CAAC;YACH,CAAC;QACH,CAAC;aAAM,IAAI,IAAI,KAAK,kBAAkB,CAAC,MAAM,EAAE,CAAC;YAC9C,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC/B,MAAM,EAAE,CAAC,EAAE;qBACR,UAAU,CAAC,MAAM,CAAC;qBAClB,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,QAAQ,CAAC;qBAClC,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,OAAO,CAAC;qBACjC,OAAO,EAAE,CAAA;YACd,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;gBAC9B,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;oBACjD,MAAM,EAAE,CAAC,EAAE;yBACR,UAAU,CAAC,WAAW,CAAC;yBACvB,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,QAAQ,CAAC;yBAClC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC;yBAC9B,OAAO,EAAE,CAAA;gBACd,CAAC;qBAAM,CAAC;oBACN,MAAM,EAAE,CAAC,EAAE;yBACR,UAAU,CAAC,aAAa,CAAC;yBACzB,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,QAAQ,CAAC;yBAClC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC;yBAC9B,OAAO,EAAE,CAAA;gBACd,CAAC;YACH,CAAC;QACH,CAAC;aAAM,IAAI,IAAI,KAAK,kBAAkB,CAAC,KAAK,EAAE,CAAC;YAC7C,MAAM,EAAE,CAAC,EAAE;iBACR,UAAU,CAAC,MAAM,CAAC;iBAClB,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,QAAQ,CAAC;iBAClC,OAAO,EAAE,CAAA;YACZ,MAAM,EAAE,CAAC,EAAE;iBACR,UAAU,CAAC,WAAW,CAAC;iBACvB,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,QAAQ,CAAC;iBAClC,OAAO,EAAE,CAAA;QACd,CAAC;QAED,OAAO,EAAE,CAAA;IACX,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;IACpC,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,GAAG;QACzB,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAA;QAClC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,EAAE,CAAC,EAAE;iBACR,UAAU,CAAC,aAAa,CAAC;iBACzB,MAAM,CAAC;gBACN,GAAG,EAAE,QAAQ;gBACb,cAAc,EAAE,QAAQ;gBACxB,cAAc,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACzC,CAAC;iBACD,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,CACjB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC,CAC3D;iBACA,OAAO,EAAE,CAAA;QACd,CAAC;QACD,OAAO,EAAE,CAAA;IACX,CAAC;IAED,KAAK,CAAC,mBAAmB;QACvB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;IACpC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,GAAG;QACpB,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAA;QACzD,MAAM,CACJ,MAAM,KAAK,MAAM,CAAC,MAAM;YACtB,MAAM,KAAK,MAAM,CAAC,MAAM;YACxB,MAAM,KAAK,MAAM,CAAC,MAAM,EAC1B,uBAAuB,MAAM,EAAE,CAChC,CAAA;QAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QAEpC,qCAAqC;QACrC,MAAM,sBAAsB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;QAE1C,mDAAmD;QACnD,IAAI,CAAC;YACH,IACE,SAAS;gBACT,UAAU,CAAC,kDAAkD,CAAC,KAAK,EACnE,CAAC;gBACD,MAAM,0CAA0C,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YAChE,CAAC;iBAAM,IACL,SAAS,KAAK,UAAU,CAAC,qCAAqC,CAAC,KAAK,EACpE,CAAC;gBACD,MAAM,gCAAgC,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YACtD,CAAC;iBAAM,IACL,SAAS,KAAK,UAAU,CAAC,4BAA4B,CAAC,KAAK,EAC3D,CAAC;gBACD,MAAM,kCAAkC,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YACxD,CAAC;iBAAM,IAAI,SAAS,KAAK,UAAU,CAAC,2BAA2B,CAAC,KAAK,EAAE,CAAC;gBACtE,MAAM,uBAAuB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YAC7C,CAAC;iBAAM,IAAI,SAAS,KAAK,UAAU,CAAC,2BAA2B,CAAC,KAAK,EAAE,CAAC;gBACtE,MAAM,oBAAoB,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YAC1C,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,UAAU,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,iCAAiC,CAAC,CAAA;QACxE,CAAC;QAED,OAAO;YACL,SAAS,EAAE;gBACT,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE;gBACjB,QAAQ;gBACR,SAAS;gBACT,GAAG;gBACH,MAAM;gBACN,OAAO;aACR;SACF,CAAA;IACH,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;IACpC,CAAC;IAED,KAAK,CAAC,IAAI;QACR,OAAO,EAAE,CAAA;IACX,CAAC;CACF,CAAC,CAAA;AAEJ,0CAA0C;AAC1C,MAAM,sBAAsB,GAAG,KAAK,EAClC,EAAY,EACZ,GAAwB,EACxB,GAAW,EACX,EAAE;IACF,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAA;IACzD,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QACzD,MAAM,EAAE,CAAC,EAAE;aACR,UAAU,CAAC,cAAc,CAAC;aAC1B,MAAM,CAAC;YACN,QAAQ;YACR,SAAS;YACT,GAAG;YACH,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC9C,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;SACf,CAAC;aACD,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,CACjB,EAAE,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC;YACvD,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,CAAC;YACnC,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,WAAW,CAAC;SACxC,CAAC,CACH;aACA,OAAO,EAAE,CAAA;IACd,CAAC;SAAM,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QACpC,MAAM,EAAE,CAAC,EAAE;aACR,UAAU,CAAC,cAAc,CAAC;aAC1B,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,QAAQ,CAAC;aAChC,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,SAAS,CAAC;aAClC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;aACtB,OAAO,EAAE,CAAA;IACd,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,EAAE,CAAC,CAAA;IAC5C,CAAC;AACH,CAAC,CAAA;AAED,MAAM,0CAA0C,GAAG,KAAK,EACtD,EAAY,EACZ,GAAwB,EACxB,GAAW,EACX,EAAE;IACF,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAA;IAE9C,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC,EAAE;aACT,UAAU,CAAC,uBAAuB,CAAC;aACnC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,CAAC;aAC/B,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;aACtB,OAAO,EAAE,CAAA;IACd,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IAClD,MAAM,MAAM,GACV,QAAQ,CAAyD,IAAI,CAAC,CAAA;IACxE,MAAM,EACJ,OAAO,EACP,oBAAoB,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GACtC,GAAG,MAAM,CAAA;IAEV,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC,EAAE;aACT,UAAU,CAAC,uBAAuB,CAAC;aACnC,MAAM,CAAC;YACN,OAAO,EAAE,QAAQ;YACjB,UAAU,EAAE,OAAO;YACnB,GAAG;YACH,SAAS,EAAE,GAAG;YACd,IAAI;YACJ,KAAK;SACN,CAAC;aACD,OAAO,EAAE,CAAA;IACd,CAAC;IAED,OAAO,EAAE,CAAC,EAAE;SACT,WAAW,CAAC,uBAAuB,CAAC;SACpC,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,CAAC;SAC/B,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;SACtB,GAAG,CAAC;QACH,SAAS,EAAE,GAAG;QACd,IAAI;QACJ,KAAK;KACN,CAAC;SACD,OAAO,EAAE,CAAA;AACd,CAAC,CAAA;AAED,MAAM,gCAAgC,GAAG,KAAK,EAC5C,EAAY,EACZ,GAAwB,EACxB,IAAY,EACZ,EAAE;IACF,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAA;IACzC,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM;QAAE,OAAM;IAEpC,MAAM,MAAM,GAAG,QAAQ,CACrB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CACtC,CAAA;IAED,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAA;IAEpC,MAAM,MAAM,GAAG;QACb,kBAAkB,EAAE,MAAM;QAC1B,2BAA2B,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;KAC1E,CAAA;IAED,OAAO,EAAE,CAAC,EAAE;SACT,WAAW,CAAC,OAAO,CAAC;SACpB,GAAG,CAAC,MAAM,CAAC;SACX,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,CAAC;SAC3B,OAAO,EAAE,CAAA;AACd,CAAC,CAAA;AAED,MAAM,kCAAkC,GAAG,KAAK,EAC9C,EAAY,EACZ,GAAwB,EACxB,IAAY,EACZ,EAAE;IACF,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAA;IACzC,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM;QAAE,OAAM;IAEpC,MAAM,MAAM,GAAG,QAAQ,CACrB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CACtC,CAAA;IAED,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,CAAA;IAErE,MAAM,MAAM,GAAG;QACb,kBAAkB,EAAE,MAAM;QAC1B,2BAA2B,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QACzE,kBAAkB,EAAE,MAAM;QAC1B,uBAAuB,EAAE,WAAW;QACpC,sBAAsB,EAAE,UAAU;KACnC,CAAA;IAED,OAAO,EAAE,CAAC,EAAE;SACT,WAAW,CAAC,OAAO,CAAC;SACpB,GAAG,CAAC,MAAM,CAAC;SACX,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,CAAC;SAC3B,OAAO,EAAE,CAAA;AACd,CAAC,CAAA;AAED,MAAM,uBAAuB,GAAG,KAAK,EACnC,EAAY,EACZ,GAAwB,EACxB,GAAW,EACX,EAAE;IACF,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAA;IAE9C,MAAM,SAAS,GAAG,CAAC,GAAW,EAAE,KAAe,EAAE,EAAE;QACjD,OAAO,KAAK,CAAC,EAAE;aACZ,UAAU,CAAC,UAAU,CAAC;aACtB,MAAM,CAAC;YACN,GAAG;YACH,aAAa,EAAE,KAAK,CAAC,EAAE;iBACpB,UAAU,CAAC,UAAU,CAAC;iBACtB,KAAK,CAAC,qBAAqB,EAAE,GAAG,EAAE,GAAG,CAAC;iBACtC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;SAChC,CAAC;aACD,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,CACjB,EAAE;aACC,MAAM,CAAC,KAAK,CAAC;aACb,WAAW,CAAC,EAAE,aAAa,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,EAAE,eAAe,CAAC,EAAE,CAAC,CACvE;aACA,OAAO,EAAE,CAAA;IACd,CAAC,CAAA;IAED,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,QAAQ,CACrB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CACtC,CAAA;QACD,MAAM,EACJ,OAAO,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GACtB,GAAG,MAAM,CAAA;QAEV,MAAM,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACnC,MAAM,KAAK,CAAC,EAAE;iBACX,UAAU,CAAC,UAAU,CAAC;iBACtB,MAAM,CAAC;gBACN,OAAO,EAAE,QAAQ;gBACjB,GAAG;gBACH,SAAS,EAAE,GAAG;gBACd,UAAU,EAAE,GAAG;gBACf,UAAU,EAAE,GAAG;aAChB,CAAC;iBACD,OAAO,EAAE,CAAA;YAEZ,MAAM,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAC7B,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACnC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,EAAE;iBAC5B,UAAU,CAAC,UAAU,CAAC;iBACtB,SAAS,EAAE;iBACX,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,CAAC;iBAC/B,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;iBACtB,gBAAgB,EAAE,CAAA;YAErB,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,KAAK,CAAC,EAAE;qBACX,UAAU,CAAC,UAAU,CAAC;qBACtB,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,CAAC;qBAC/B,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;qBACtB,OAAO,EAAE,CAAA;gBAEZ,MAAM,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC,CAAA;YAC7C,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;AACH,CAAC,CAAA;AAED,MAAM,oBAAoB,GAAG,KAAK,EAChC,EAAY,EACZ,GAAwB,EACxB,GAAW,EACX,EAAE;IACF,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAA;IAE9C,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;QAE3D,MAAM,EAAE,CAAC,EAAE;aACR,UAAU,CAAC,OAAO,CAAC;aACnB,MAAM,CAAC;YACN,OAAO,EAAE,QAAQ;YACjB,GAAG;YACH,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;YACd,OAAO,EAAE,aAAa;SACvB,CAAC;aACD,OAAO,EAAE,CAAA;IACd,CAAC;IAED,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;QAE3D,MAAM,EAAE,CAAC,EAAE;aACR,WAAW,CAAC,OAAO,CAAC;aACpB,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,CAAC;aAC/B,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;aACtB,GAAG,CAAC;YACH,SAAS,EAAE,GAAG;YACd,OAAO,EAAE,aAAa;SACvB,CAAC;aACD,OAAO,EAAE,CAAA;IACd,CAAC;IAED,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,EAAE,CAAC,EAAE;aACR,UAAU,CAAC,OAAO,CAAC;aACnB,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,CAAC;aAC/B,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;aACtB,OAAO,EAAE,CAAA;IACd,CAAC;AACH,CAAC,CAAA","sourcesContent":["import assert from 'node:assert'\nimport events from 'node:events'\nimport http from 'node:http'\nimport { ConnectRouter } from '@connectrpc/connect'\nimport { expressConnectMiddleware } from '@connectrpc/connect-express'\nimport express from 'express'\n// eslint-disable-next-line import/default\nimport httpTerminator from 'http-terminator'\nimport { TID } from '@atproto/common'\nimport { lexParse } from '@atproto/lex'\nimport { AtUri } from '@atproto/syntax'\nimport { app } from '../../lexicons/index.js'\nimport { httpLogger } from '../../logger.js'\nimport { Service } from '../../proto/bsync_connect.js'\nimport {\n Method,\n MuteOperation_Type,\n PutOperationRequest,\n} from '../../proto/bsync_pb.js'\nimport { Namespaces } from '../../stash.js'\nimport { Database } from '../server/db/index.js'\nimport { countAll, excluded } from '../server/db/util.js'\n\nexport class MockBsync {\n private terminator: httpTerminator.HttpTerminator\n\n constructor(public server: http.Server) {\n this.terminator = httpTerminator.createHttpTerminator({ server })\n }\n\n static async create(db: Database, port: number) {\n const app = express()\n const routes = createRoutes(db)\n app.use(expressConnectMiddleware({ routes }))\n const server = app.listen(port)\n await events.once(server, 'listening')\n return new MockBsync(server)\n }\n\n async destroy() {\n await this.terminator.terminate()\n }\n\n async [Symbol.asyncDispose]() {\n await this.destroy()\n }\n}\n\nconst createRoutes = (db: Database) => (router: ConnectRouter) =>\n router.service(Service, {\n async addMuteOperation(req) {\n const { type, actorDid, subject } = req\n if (type === MuteOperation_Type.ADD) {\n if (subject.startsWith('did:')) {\n assert(actorDid !== subject, 'cannot mute yourself') // @TODO pass message through in http error\n await db.db\n .insertInto('mute')\n .values({\n mutedByDid: actorDid,\n subjectDid: subject,\n createdAt: new Date().toISOString(),\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n } else {\n const uri = new AtUri(subject)\n if (uri.collection === app.bsky.graph.list.$type) {\n await db.db\n .insertInto('list_mute')\n .values({\n mutedByDid: actorDid,\n listUri: subject,\n createdAt: new Date().toISOString(),\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n } else {\n await db.db\n .insertInto('thread_mute')\n .values({\n mutedByDid: actorDid,\n rootUri: subject,\n createdAt: new Date().toISOString(),\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n }\n }\n } else if (type === MuteOperation_Type.REMOVE) {\n if (subject.startsWith('did:')) {\n await db.db\n .deleteFrom('mute')\n .where('mutedByDid', '=', actorDid)\n .where('subjectDid', '=', subject)\n .execute()\n } else {\n const uri = new AtUri(subject)\n if (uri.collection === app.bsky.graph.list.$type) {\n await db.db\n .deleteFrom('list_mute')\n .where('mutedByDid', '=', actorDid)\n .where('listUri', '=', subject)\n .execute()\n } else {\n await db.db\n .deleteFrom('thread_mute')\n .where('mutedByDid', '=', actorDid)\n .where('rootUri', '=', subject)\n .execute()\n }\n }\n } else if (type === MuteOperation_Type.CLEAR) {\n await db.db\n .deleteFrom('mute')\n .where('mutedByDid', '=', actorDid)\n .execute()\n await db.db\n .deleteFrom('list_mute')\n .where('mutedByDid', '=', actorDid)\n .execute()\n }\n\n return {}\n },\n\n async scanMuteOperations() {\n throw new Error('not implemented')\n },\n\n async addNotifOperation(req) {\n const { actorDid, priority } = req\n if (priority !== undefined) {\n await db.db\n .insertInto('actor_state')\n .values({\n did: actorDid,\n priorityNotifs: priority,\n lastSeenNotifs: new Date().toISOString(),\n })\n .onConflict((oc) =>\n oc.column('did').doUpdateSet({ priorityNotifs: priority }),\n )\n .execute()\n }\n return {}\n },\n\n async scanNotifOperations() {\n throw new Error('not implemented')\n },\n\n async putOperation(req) {\n const { actorDid, namespace, key, method, payload } = req\n assert(\n method === Method.CREATE ||\n method === Method.UPDATE ||\n method === Method.DELETE,\n `Unsupported method: ${method}`,\n )\n\n const now = new Date().toISOString()\n\n // Index all items into private_data.\n await handleGenericOperation(db, req, now)\n\n // Maintain bespoke indexes for certain namespaces.\n try {\n if (\n namespace ===\n Namespaces.AppBskyNotificationDefsSubjectActivitySubscription.$type\n ) {\n await handleSubjectActivitySubscriptionOperation(db, req, now)\n } else if (\n namespace === Namespaces.AppBskyUnspeccedDefsAgeAssuranceEvent.$type\n ) {\n await handleAgeAssuranceEventOperation(db, req, now)\n } else if (\n namespace === Namespaces.AppBskyAgeassuranceDefsEvent.$type\n ) {\n await handleAgeAssuranceV2EventOperation(db, req, now)\n } else if (namespace === Namespaces.AppBskyBookmarkDefsBookmark.$type) {\n await handleBookmarkOperation(db, req, now)\n } else if (namespace === Namespaces.AppBskyDraftDefsDraftWithId.$type) {\n await handleDraftOperation(db, req, now)\n }\n } catch (err) {\n httpLogger.warn({ err, namespace }, 'mock bsync put operation failed')\n }\n\n return {\n operation: {\n id: TID.nextStr(),\n actorDid,\n namespace,\n key,\n method,\n payload,\n },\n }\n },\n\n async scanOperations() {\n throw new Error('not implemented')\n },\n\n async ping() {\n return {}\n },\n })\n\n// upsert into or remove from private_data\nconst handleGenericOperation = async (\n db: Database,\n req: PutOperationRequest,\n now: string,\n) => {\n const { actorDid, namespace, key, method, payload } = req\n if (method === Method.CREATE || method === Method.UPDATE) {\n await db.db\n .insertInto('private_data')\n .values({\n actorDid,\n namespace,\n key,\n payload: Buffer.from(payload).toString('utf8'),\n indexedAt: now,\n updatedAt: now,\n })\n .onConflict((oc) =>\n oc.columns(['actorDid', 'namespace', 'key']).doUpdateSet({\n payload: excluded(db.db, 'payload'),\n updatedAt: excluded(db.db, 'updatedAt'),\n }),\n )\n .execute()\n } else if (method === Method.DELETE) {\n await db.db\n .deleteFrom('private_data')\n .where('actorDid', '=', actorDid)\n .where('namespace', '=', namespace)\n .where('key', '=', key)\n .execute()\n } else {\n assert.fail(`unexpected method ${method}`)\n }\n}\n\nconst handleSubjectActivitySubscriptionOperation = async (\n db: Database,\n req: PutOperationRequest,\n now: string,\n) => {\n const { actorDid, key, method, payload } = req\n\n if (method === Method.DELETE) {\n return db.db\n .deleteFrom('activity_subscription')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .execute()\n }\n\n const json = Buffer.from(payload).toString('utf8')\n const parsed =\n lexParse<app.bsky.notification.defs.SubjectActivitySubscription>(json)\n const {\n subject,\n activitySubscription: { post, reply },\n } = parsed\n\n if (method === Method.CREATE) {\n return db.db\n .insertInto('activity_subscription')\n .values({\n creator: actorDid,\n subjectDid: subject,\n key,\n indexedAt: now,\n post,\n reply,\n })\n .execute()\n }\n\n return db.db\n .updateTable('activity_subscription')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .set({\n indexedAt: now,\n post,\n reply,\n })\n .execute()\n}\n\nconst handleAgeAssuranceEventOperation = async (\n db: Database,\n req: PutOperationRequest,\n _now: string,\n) => {\n const { actorDid, method, payload } = req\n if (method !== Method.CREATE) return\n\n const parsed = lexParse<app.bsky.unspecced.defs.AgeAssuranceEvent>(\n Buffer.from(payload).toString('utf8'),\n )\n\n const { status, createdAt } = parsed\n\n const update = {\n ageAssuranceStatus: status,\n ageAssuranceLastInitiatedAt: status === 'pending' ? createdAt : undefined,\n }\n\n return db.db\n .updateTable('actor')\n .set(update)\n .where('did', '=', actorDid)\n .execute()\n}\n\nconst handleAgeAssuranceV2EventOperation = async (\n db: Database,\n req: PutOperationRequest,\n _now: string,\n) => {\n const { actorDid, method, payload } = req\n if (method !== Method.CREATE) return\n\n const parsed = lexParse<app.bsky.ageassurance.defs.Event>(\n Buffer.from(payload).toString('utf8'),\n )\n\n const { status, createdAt, access, countryCode, regionCode } = parsed\n\n const update = {\n ageAssuranceStatus: status,\n ageAssuranceLastInitiatedAt: status === 'pending' ? createdAt : undefined,\n ageAssuranceAccess: access,\n ageAssuranceCountryCode: countryCode,\n ageAssuranceRegionCode: regionCode,\n }\n\n return db.db\n .updateTable('actor')\n .set(update)\n .where('did', '=', actorDid)\n .execute()\n}\n\nconst handleBookmarkOperation = async (\n db: Database,\n req: PutOperationRequest,\n now: string,\n) => {\n const { actorDid, key, method, payload } = req\n\n const updateAgg = (uri: string, dbTxn: Database) => {\n return dbTxn.db\n .insertInto('post_agg')\n .values({\n uri,\n bookmarkCount: dbTxn.db\n .selectFrom('bookmark')\n .where('bookmark.subjectUri', '=', uri)\n .select(countAll.as('count')),\n })\n .onConflict((oc) =>\n oc\n .column('uri')\n .doUpdateSet({ bookmarkCount: excluded(dbTxn.db, 'bookmarkCount') }),\n )\n .execute()\n }\n\n if (method === Method.CREATE) {\n const parsed = lexParse<app.bsky.bookmark.defs.Bookmark>(\n Buffer.from(payload).toString('utf8'),\n )\n const {\n subject: { uri, cid },\n } = parsed\n\n await db.transaction(async (dbTxn) => {\n await dbTxn.db\n .insertInto('bookmark')\n .values({\n creator: actorDid,\n key,\n indexedAt: now,\n subjectUri: uri,\n subjectCid: cid,\n })\n .execute()\n\n await updateAgg(uri, dbTxn)\n })\n }\n\n if (method === Method.DELETE) {\n await db.transaction(async (dbTxn) => {\n const bookmark = await dbTxn.db\n .selectFrom('bookmark')\n .selectAll()\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .executeTakeFirst()\n\n if (bookmark) {\n await dbTxn.db\n .deleteFrom('bookmark')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .execute()\n\n await updateAgg(bookmark.subjectUri, dbTxn)\n }\n })\n }\n}\n\nconst handleDraftOperation = async (\n db: Database,\n req: PutOperationRequest,\n now: string,\n) => {\n const { actorDid, key, method, payload } = req\n\n if (method === Method.CREATE) {\n const payloadString = Buffer.from(payload).toString('utf8')\n\n await db.db\n .insertInto('draft')\n .values({\n creator: actorDid,\n key,\n createdAt: now,\n updatedAt: now,\n payload: payloadString,\n })\n .execute()\n }\n\n if (method === Method.UPDATE) {\n const payloadString = Buffer.from(payload).toString('utf8')\n\n await db.db\n .updateTable('draft')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .set({\n updatedAt: now,\n payload: payloadString,\n })\n .execute()\n }\n\n if (method === Method.DELETE) {\n await db.db\n .deleteFrom('draft')\n .where('creator', '=', actorDid)\n .where('key', '=', key)\n .execute()\n }\n}\n"]}