@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
@@ -4,41 +4,74 @@ import { subLogger as log } from '../../logger.js';
4
4
  import { BackgroundQueue } from './background.js';
5
5
  import { IndexingService } from './indexing/index.js';
6
6
  export class RepoSubscription {
7
- constructor(opts) {
8
- this.opts = opts;
9
- const { service, db, idResolver } = opts;
10
- this.background = new BackgroundQueue(db);
11
- this.indexingSvc = new IndexingService(db, idResolver, this.background);
12
- const { runner, firehose } = createFirehose({
13
- idResolver,
14
- service,
15
- indexingSvc: this.indexingSvc,
7
+ constructor({ service, db, idResolver, }) {
8
+ this.abortController = new AbortController();
9
+ this.service = service;
10
+ this.idResolver = idResolver;
11
+ this.background = new BackgroundQueue(db, {
12
+ // @TODO This has historically been using the default concurrency
13
+ // (Infinity) but we may want to limit this in the future to avoid
14
+ // overloading the database with indexing tasks.
15
+ concurrency: Number.POSITIVE_INFINITY,
16
16
  });
17
- this.runner = runner;
18
- this.firehose = firehose;
17
+ this.indexingSvc = new IndexingService(db, idResolver, this.background);
18
+ }
19
+ get destroyed() {
20
+ return this.abortController.signal.aborted;
21
+ }
22
+ get running() {
23
+ return this.current != null;
19
24
  }
20
- start() {
21
- this.firehose.start();
25
+ getCursor() {
26
+ return this.current?.runner.getCursor();
27
+ }
28
+ async start() {
29
+ this.abortController.signal.throwIfAborted();
30
+ if (!this.current) {
31
+ this.current = createFirehose({
32
+ idResolver: this.idResolver,
33
+ service: this.service,
34
+ indexingSvc: this.indexingSvc,
35
+ });
36
+ void this.current.firehose.start();
37
+ }
38
+ }
39
+ async stop() {
40
+ try {
41
+ if (this.current) {
42
+ const { firehose, runner } = this.current;
43
+ this.current = undefined;
44
+ try {
45
+ await firehose.destroy();
46
+ }
47
+ finally {
48
+ await runner.destroy();
49
+ }
50
+ }
51
+ }
52
+ finally {
53
+ await this.background.processAll();
54
+ }
22
55
  }
23
56
  async restart() {
24
- await this.destroy();
25
- const { runner, firehose } = createFirehose({
26
- idResolver: this.opts.idResolver,
27
- service: this.opts.service,
28
- indexingSvc: this.indexingSvc,
29
- });
30
- this.runner = runner;
31
- this.firehose = firehose;
32
- this.start();
57
+ await this.stop();
58
+ void this.start();
33
59
  }
34
60
  async processAll() {
35
- await this.runner.processAll();
61
+ await this.current?.runner.processAll();
36
62
  await this.background.processAll();
37
63
  }
38
64
  async destroy() {
39
- await this.firehose.destroy();
40
- await this.runner.destroy();
41
- await this.background.processAll();
65
+ this.abortController.abort();
66
+ try {
67
+ await this.stop();
68
+ }
69
+ finally {
70
+ await this.background.destroy();
71
+ }
72
+ }
73
+ async [Symbol.asyncDispose]() {
74
+ await this.destroy();
42
75
  }
43
76
  }
44
77
  const createFirehose = (opts) => {
@@ -1 +1 @@
1
- {"version":3,"file":"subscription.js","sourceRoot":"","sources":["../../../src/data-plane/server/subscription.ts"],"names":[],"mappings":"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","sourcesContent":["import { IdResolver } from '@atproto/identity'\nimport { WriteOpAction } from '@atproto/repo'\nimport { Event as FirehoseEvent, Firehose, MemoryRunner } from '@atproto/sync'\nimport { subLogger as log } from '../../logger.js'\nimport { BackgroundQueue } from './background.js'\nimport { Database } from './db/index.js'\nimport { IndexingService } from './indexing/index.js'\n\nexport class RepoSubscription {\n firehose: Firehose\n runner: MemoryRunner\n background: BackgroundQueue\n indexingSvc: IndexingService\n\n constructor(\n public opts: { service: string; db: Database; idResolver: IdResolver },\n ) {\n const { service, db, idResolver } = opts\n this.background = new BackgroundQueue(db)\n this.indexingSvc = new IndexingService(db, idResolver, this.background)\n\n const { runner, firehose } = createFirehose({\n idResolver,\n service,\n indexingSvc: this.indexingSvc,\n })\n this.runner = runner\n this.firehose = firehose\n }\n\n start() {\n this.firehose.start()\n }\n\n async restart() {\n await this.destroy()\n const { runner, firehose } = createFirehose({\n idResolver: this.opts.idResolver,\n service: this.opts.service,\n indexingSvc: this.indexingSvc,\n })\n this.runner = runner\n this.firehose = firehose\n this.start()\n }\n\n async processAll() {\n await this.runner.processAll()\n await this.background.processAll()\n }\n\n async destroy() {\n await this.firehose.destroy()\n await this.runner.destroy()\n await this.background.processAll()\n }\n}\n\nconst createFirehose = (opts: {\n idResolver: IdResolver\n service: string\n indexingSvc: IndexingService\n}) => {\n const { idResolver, service, indexingSvc } = opts\n const runner = new MemoryRunner({ startCursor: 0 })\n const firehose = new Firehose({\n idResolver,\n runner,\n service,\n unauthenticatedHandles: true, // indexing service handles these\n unauthenticatedCommits: true, // @TODO there seems to be a very rare issue where the authenticator thinks a block is missing in deletion ops\n onError: (err) => log.error({ err }, 'error in subscription'),\n handleEvent: async (evt: FirehoseEvent) => {\n if (evt.event === 'identity') {\n await indexingSvc.indexHandle(evt.did, evt.time, true)\n } else if (evt.event === 'account') {\n if (evt.active === false && evt.status === 'deleted') {\n await indexingSvc.deleteActor(evt.did)\n } else {\n await indexingSvc.updateActorStatus(evt.did, evt.active, evt.status)\n }\n } else if (evt.event === 'sync') {\n await Promise.all([\n indexingSvc.setCommitLastSeen(evt.did, evt.cid, evt.rev),\n indexingSvc.indexHandle(evt.did, evt.time),\n ])\n } else {\n const indexFn =\n evt.event === 'delete'\n ? indexingSvc.deleteRecord(evt.uri)\n : indexingSvc.indexRecord(\n evt.uri,\n evt.cid,\n evt.record,\n evt.event === 'create'\n ? WriteOpAction.Create\n : WriteOpAction.Update,\n evt.time,\n )\n await Promise.all([\n indexFn,\n indexingSvc.setCommitLastSeen(evt.did, evt.commit, evt.rev),\n indexingSvc.indexHandle(evt.did, evt.time),\n ])\n }\n },\n })\n return { firehose, runner }\n}\n"]}
1
+ {"version":3,"file":"subscription.js","sourceRoot":"","sources":["../../../src/data-plane/server/subscription.ts"],"names":[],"mappings":"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","sourcesContent":["import { IdResolver } from '@atproto/identity'\nimport { WriteOpAction } from '@atproto/repo'\nimport { Event as FirehoseEvent, Firehose, MemoryRunner } from '@atproto/sync'\nimport { subLogger as log } from '../../logger.js'\nimport { BackgroundQueue } from './background.js'\nimport { Database } from './db/index.js'\nimport { IndexingService } from './indexing/index.js'\n\nexport class RepoSubscription {\n private readonly abortController = new AbortController()\n private current?: ReturnType<typeof createFirehose>\n readonly background: BackgroundQueue<Database>\n readonly indexingSvc: IndexingService\n private readonly service: string\n private readonly idResolver: IdResolver\n\n constructor({\n service,\n db,\n idResolver,\n }: {\n service: string\n db: Database\n idResolver: IdResolver\n }) {\n this.service = service\n this.idResolver = idResolver\n this.background = new BackgroundQueue(db, {\n // @TODO This has historically been using the default concurrency\n // (Infinity) but we may want to limit this in the future to avoid\n // overloading the database with indexing tasks.\n concurrency: Number.POSITIVE_INFINITY,\n })\n this.indexingSvc = new IndexingService(db, idResolver, this.background)\n }\n\n get destroyed() {\n return this.abortController.signal.aborted\n }\n\n get running() {\n return this.current != null\n }\n\n getCursor() {\n return this.current?.runner.getCursor()\n }\n\n async start() {\n this.abortController.signal.throwIfAborted()\n\n if (!this.current) {\n this.current = createFirehose({\n idResolver: this.idResolver,\n service: this.service,\n indexingSvc: this.indexingSvc,\n })\n void this.current.firehose.start()\n }\n }\n\n async stop() {\n try {\n if (this.current) {\n const { firehose, runner } = this.current\n this.current = undefined\n try {\n await firehose.destroy()\n } finally {\n await runner.destroy()\n }\n }\n } finally {\n await this.background.processAll()\n }\n }\n\n async restart() {\n await this.stop()\n void this.start()\n }\n\n async processAll() {\n await this.current?.runner.processAll()\n await this.background.processAll()\n }\n\n async destroy() {\n this.abortController.abort()\n try {\n await this.stop()\n } finally {\n await this.background.destroy()\n }\n }\n\n async [Symbol.asyncDispose]() {\n await this.destroy()\n }\n}\n\nconst createFirehose = (opts: {\n idResolver: IdResolver\n service: string\n indexingSvc: IndexingService\n}) => {\n const { idResolver, service, indexingSvc } = opts\n const runner = new MemoryRunner({ startCursor: 0 })\n const firehose = new Firehose({\n idResolver,\n runner,\n service,\n unauthenticatedHandles: true, // indexing service handles these\n unauthenticatedCommits: true, // @TODO there seems to be a very rare issue where the authenticator thinks a block is missing in deletion ops\n onError: (err) => log.error({ err }, 'error in subscription'),\n handleEvent: async (evt: FirehoseEvent) => {\n if (evt.event === 'identity') {\n await indexingSvc.indexHandle(evt.did, evt.time, true)\n } else if (evt.event === 'account') {\n if (evt.active === false && evt.status === 'deleted') {\n await indexingSvc.deleteActor(evt.did)\n } else {\n await indexingSvc.updateActorStatus(evt.did, evt.active, evt.status)\n }\n } else if (evt.event === 'sync') {\n await Promise.all([\n indexingSvc.setCommitLastSeen(evt.did, evt.cid, evt.rev),\n indexingSvc.indexHandle(evt.did, evt.time),\n ])\n } else {\n const indexFn =\n evt.event === 'delete'\n ? indexingSvc.deleteRecord(evt.uri)\n : indexingSvc.indexRecord(\n evt.uri,\n evt.cid,\n evt.record,\n evt.event === 'create'\n ? WriteOpAction.Create\n : WriteOpAction.Update,\n evt.time,\n )\n await Promise.all([\n indexFn,\n indexingSvc.setCommitLastSeen(evt.did, evt.commit, evt.rev),\n indexingSvc.indexHandle(evt.did, evt.time),\n ])\n }\n },\n })\n return { firehose, runner }\n}\n"]}
@@ -19,7 +19,8 @@ export declare class FeatureGatesClient {
19
19
  eventProxyTrackingEndpoint?: string;
20
20
  });
21
21
  start(): Promise<void>;
22
- destroy(): void;
22
+ destroy(): Promise<void>;
23
+ [Symbol.asyncDispose](): Promise<void>;
23
24
  /**
24
25
  * Evaluate multiple feature gates for a given user, returning a map of gate
25
26
  * ID to boolean result.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/feature-gates/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAElC,OAAO,EAAE,IAAI,EAA4B,MAAM,YAAY,CAAA;AAE3D,OAAO,EAEL,wBAAwB,EACxB,WAAW,EACZ,MAAM,YAAY,CAAA;AA0BnB,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAE1D,qBAAa,kBAAkB;IAa3B,OAAO,CAAC,MAAM;IAZhB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAA0C;IACxD,OAAO,CAAC,eAAe,CAAwC;IAC/D,OAAO,CAAC,OAAO,CAAe;IAE9B;;;OAGG;IACH,IAAI,cAAO;IAEX,YACU,MAAM,EAAE;QACd,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAA;QAC5B,0BAA0B,CAAC,EAAE,MAAM,CAAA;KACpC,EAKF;IAEK,KAAK,kBA6FV;IAED,OAAO,SAQN;IAED;;;OAGG;IACH,OAAO,CAAC,UAAU;IAUlB,KAAK,CAAC,iBAAiB,EAAE,WAAW,GAAG,wBAAwB,CAoB9D;IAED;;;;;OAKG;IACH,2BAA2B,CAAC,EAC1B,MAAM,EACN,GAAG,GACJ,EAAE;QACD;;WAEG;QACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;QACrB;;WAEG;QACH,GAAG,EAAE,OAAO,CAAC,OAAO,CAAA;KACrB,GAAG,WAAW,CASd;CACF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/feature-gates/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAElC,OAAO,EAAE,IAAI,EAA4B,MAAM,YAAY,CAAA;AAE3D,OAAO,EAEL,wBAAwB,EACxB,WAAW,EACZ,MAAM,YAAY,CAAA;AA0BnB,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAE1D,qBAAa,kBAAkB;IAa3B,OAAO,CAAC,MAAM;IAZhB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,MAAM,CAA0C;IACxD,OAAO,CAAC,eAAe,CAAwC;IAC/D,OAAO,CAAC,OAAO,CAAe;IAE9B;;;OAGG;IACH,IAAI,cAAO;IAEX,YACU,MAAM,EAAE;QACd,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAA;QAC5B,0BAA0B,CAAC,EAAE,MAAM,CAAA;KACpC,EAKF;IAEK,KAAK,kBA6FV;IAEK,OAAO,kBAQZ;IAEK,CAAC,MAAM,CAAC,YAAY,CAAC,kBAE1B;IAED;;;OAGG;IACH,OAAO,CAAC,UAAU;IAUlB,KAAK,CAAC,iBAAiB,EAAE,WAAW,GAAG,wBAAwB,CAoB9D;IAED;;;;;OAKG;IACH,2BAA2B,CAAC,EAC1B,MAAM,EACN,GAAG,GACJ,EAAE;QACD;;WAEG;QACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;QACrB;;WAEG;QACH,GAAG,EAAE,OAAO,CAAC,OAAO,CAAA;KACrB,GAAG,WAAW,CASd;CACF"}
@@ -42,17 +42,17 @@ export class FeatureGatesClient {
42
42
  this.client = new GrowthBookClient({
43
43
  apiHost: this.config.growthBookApiHost,
44
44
  clientKey: this.config.growthBookClientKey,
45
- onFeatureUsage: (feature, result, userContext) => {
45
+ onFeatureUsage: async (feature, result, userContext) => {
46
46
  if (IGNORE_METRICS_FOR_GATES.has(feature))
47
47
  return;
48
- this.metrics.track('feature:viewed', {
48
+ await this.metrics.track('feature:viewed', {
49
49
  featureId: feature,
50
50
  featureResultValue: result.value,
51
51
  experimentId: result.experiment?.key,
52
52
  variationId: result.experimentResult?.key,
53
53
  }, parsedUserContextToTrackingMetadata(extractUserContextFromGrowthbookUserContext(userContext)));
54
54
  },
55
- trackingCallback: (experiment, result, userContext) => {
55
+ trackingCallback: async (experiment, result, userContext) => {
56
56
  /**
57
57
  * Experiments are only fired in a feature gate has an Experiment
58
58
  * attached in Growthbook. Howerver, we want to be extra sure that a
@@ -62,7 +62,7 @@ export class FeatureGatesClient {
62
62
  if (result.featureId &&
63
63
  IGNORE_METRICS_FOR_GATES.has(result.featureId))
64
64
  return;
65
- this.metrics.track('experiment:viewed', {
65
+ await this.metrics.track('experiment:viewed', {
66
66
  experimentId: experiment.key,
67
67
  variationId: result.key,
68
68
  }, parsedUserContextToTrackingMetadata(extractUserContextFromGrowthbookUserContext(userContext)));
@@ -103,14 +103,17 @@ export class FeatureGatesClient {
103
103
  featureGatesLogger.error({ err }, 'Client initialization failed');
104
104
  }
105
105
  }
106
- destroy() {
106
+ async destroy() {
107
107
  if (this.ready) {
108
108
  this.ready = false;
109
109
  if (this.refreshInterval) {
110
110
  clearInterval(this.refreshInterval);
111
111
  }
112
112
  }
113
- this.metrics.stop();
113
+ await this.metrics.stop();
114
+ }
115
+ async [Symbol.asyncDispose]() {
116
+ await this.destroy();
114
117
  }
115
118
  /**
116
119
  * Evaluate multiple feature gates for a given user, returning a map of gate
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/feature-gates/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { GrowthBookClient } from '@growthbook/growthbook'\nimport type express from 'express'\nimport { featureGatesLogger } from '../logger.js'\nimport { Gate, IGNORE_METRICS_FOR_GATES } from './gates.js'\nimport { MetricsClient } from './metrics.js'\nimport {\n CheckedFeatureGatesMap,\n ScopedFeatureGatesClient,\n UserContext,\n} from './types.js'\nimport {\n extractUserContextFromGrowthbookUserContext,\n mergeUserContexts,\n normalizeUserContext,\n parsedUserContextToTrackingMetadata,\n} from './utils.js'\n\n/**\n * We want this to be sufficiently high that we don't time out under\n * normal conditions, but not so high that it takes too long to boot\n * the server.\n */\nconst FETCH_TIMEOUT = 3e3 // 3 seconds\n\n/**\n * StatSig used to default to every 10s, but I think 1m is fine\n */\nconst REFETCH_INTERVAL = 60e3 // 1 minute\n\n/**\n * These need to match what the client sends\n */\nconst ANALYTICS_HEADER_DEVICE_ID = 'X-Bsky-Device-Id'\nconst ANALYTICS_HEADER_SESSION_ID = 'X-Bsky-Session-Id'\n\nexport { type ScopedFeatureGatesClient } from './types.js'\n\nexport class FeatureGatesClient {\n private ready = false\n private client: GrowthBookClient | undefined = undefined\n private refreshInterval: NodeJS.Timeout | undefined = undefined\n private metrics: MetricsClient\n\n /**\n * Easy access to the `Gate` enum for consumers of this class, so they don't\n * need to import it separately.\n */\n Gate = Gate\n\n constructor(\n private config: {\n growthBookApiHost?: string\n growthBookClientKey?: string\n eventProxyTrackingEndpoint?: string\n },\n ) {\n this.metrics = new MetricsClient({\n trackingEndpoint: config.eventProxyTrackingEndpoint,\n })\n }\n\n async start() {\n if (!this.config.growthBookApiHost || !this.config.growthBookClientKey) {\n featureGatesLogger.info(\n {},\n 'feature gates not configured, skipping initialization',\n )\n return\n }\n\n try {\n this.client = new GrowthBookClient({\n apiHost: this.config.growthBookApiHost,\n clientKey: this.config.growthBookClientKey,\n onFeatureUsage: (feature, result, userContext) => {\n if (IGNORE_METRICS_FOR_GATES.has(feature as Gate)) return\n\n this.metrics.track(\n 'feature:viewed',\n {\n featureId: feature,\n featureResultValue: result.value,\n experimentId: result.experiment?.key,\n variationId: result.experimentResult?.key,\n },\n parsedUserContextToTrackingMetadata(\n extractUserContextFromGrowthbookUserContext(userContext),\n ),\n )\n },\n trackingCallback: (experiment, result, userContext) => {\n /**\n * Experiments are only fired in a feature gate has an Experiment\n * attached in Growthbook. Howerver, we want to be extra sure that a\n * misconfigured experiment doesn't result in a huge increase in events, so we\n * protect this here.\n */\n if (\n result.featureId &&\n IGNORE_METRICS_FOR_GATES.has(result.featureId as Gate)\n )\n return\n\n this.metrics.track(\n 'experiment:viewed',\n {\n experimentId: experiment.key,\n variationId: result.key,\n },\n parsedUserContextToTrackingMetadata(\n extractUserContextFromGrowthbookUserContext(userContext),\n ),\n )\n },\n })\n\n const { source, error } = await this.client.init({\n timeout: FETCH_TIMEOUT,\n })\n\n /**\n * This does not necessarily mean that the client completely failed,\n * since it could just be that the request timed out. It may succeed\n * after the timeout, or later during refreshes.\n *\n * @see https://docs.growthbook.io/lib/node#error-handling\n */\n if (error) {\n featureGatesLogger.error(\n { err: error, source },\n 'Client failed to initialize normally',\n )\n }\n\n /**\n * Set up periodic refresh of feature definitions\n *\n * @see https://docs.growthbook.io/lib/node#refreshing-features\n */\n this.refreshInterval = setInterval(async () => {\n try {\n await this.client?.refreshFeatures({\n timeout: FETCH_TIMEOUT,\n })\n } catch (err) {\n featureGatesLogger.error({ err }, 'Failed to refresh features')\n }\n }, REFETCH_INTERVAL)\n\n /* Ready or not, here we come */\n this.ready = true\n } catch (err) {\n featureGatesLogger.error({ err }, 'Client initialization failed')\n }\n }\n\n destroy() {\n if (this.ready) {\n this.ready = false\n if (this.refreshInterval) {\n clearInterval(this.refreshInterval)\n }\n }\n this.metrics.stop()\n }\n\n /**\n * Evaluate multiple feature gates for a given user, returning a map of gate\n * ID to boolean result.\n */\n private checkGates(\n gates: Gate[],\n userContext: UserContext,\n ): CheckedFeatureGatesMap {\n const gb = this.client\n const attributes = normalizeUserContext(userContext)\n if (!gb || !this.ready) return new Map(gates.map((g) => [g, false]))\n return new Map(gates.map((g) => [g, gb.isOn(g, { attributes })]))\n }\n\n scope(scopedUserContext: UserContext): ScopedFeatureGatesClient {\n /*\n * Create initial deviceId and sessionId values for the scoped client, to\n * be used throughout this request lifecycle.\n */\n const base = normalizeUserContext(scopedUserContext)\n return {\n Gate: this.Gate,\n checkGates: (\n gates: Gate[],\n userContextOverrides?: Pick<UserContext, 'did'>,\n ) => {\n const userContext = mergeUserContexts(base, userContextOverrides)\n return this.checkGates(gates, userContext)\n },\n checkGate: (gate: Gate, userContextOverrides?: UserContext) => {\n const userContext = mergeUserContexts(base, userContextOverrides)\n return this.checkGates([gate], userContext).get(gate) || false\n },\n }\n }\n\n /**\n * Parse properties available in XRPC handlers to `UserContext`. The returned\n * proeprties are used as GrowthBook `attributes` as well as the metadata\n * payload for our analytics events. This ensures that the same user properties\n * are used for both feature gate targeting and analytics.\n */\n parseUserContextFromHandler({\n viewer,\n req,\n }: {\n /**\n * The user's DID\n */\n viewer: string | null\n /**\n * The express request object, used to extract analytics headers for the user context\n */\n req: express.Request\n }): UserContext {\n const deviceId = req.header(ANALYTICS_HEADER_DEVICE_ID)\n const sessionId = req.header(ANALYTICS_HEADER_SESSION_ID)\n\n return normalizeUserContext({\n did: viewer,\n deviceId,\n sessionId,\n })\n }\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/feature-gates/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { GrowthBookClient } from '@growthbook/growthbook'\nimport type express from 'express'\nimport { featureGatesLogger } from '../logger.js'\nimport { Gate, IGNORE_METRICS_FOR_GATES } from './gates.js'\nimport { MetricsClient } from './metrics.js'\nimport {\n CheckedFeatureGatesMap,\n ScopedFeatureGatesClient,\n UserContext,\n} from './types.js'\nimport {\n extractUserContextFromGrowthbookUserContext,\n mergeUserContexts,\n normalizeUserContext,\n parsedUserContextToTrackingMetadata,\n} from './utils.js'\n\n/**\n * We want this to be sufficiently high that we don't time out under\n * normal conditions, but not so high that it takes too long to boot\n * the server.\n */\nconst FETCH_TIMEOUT = 3e3 // 3 seconds\n\n/**\n * StatSig used to default to every 10s, but I think 1m is fine\n */\nconst REFETCH_INTERVAL = 60e3 // 1 minute\n\n/**\n * These need to match what the client sends\n */\nconst ANALYTICS_HEADER_DEVICE_ID = 'X-Bsky-Device-Id'\nconst ANALYTICS_HEADER_SESSION_ID = 'X-Bsky-Session-Id'\n\nexport { type ScopedFeatureGatesClient } from './types.js'\n\nexport class FeatureGatesClient {\n private ready = false\n private client: GrowthBookClient | undefined = undefined\n private refreshInterval: NodeJS.Timeout | undefined = undefined\n private metrics: MetricsClient\n\n /**\n * Easy access to the `Gate` enum for consumers of this class, so they don't\n * need to import it separately.\n */\n Gate = Gate\n\n constructor(\n private config: {\n growthBookApiHost?: string\n growthBookClientKey?: string\n eventProxyTrackingEndpoint?: string\n },\n ) {\n this.metrics = new MetricsClient({\n trackingEndpoint: config.eventProxyTrackingEndpoint,\n })\n }\n\n async start() {\n if (!this.config.growthBookApiHost || !this.config.growthBookClientKey) {\n featureGatesLogger.info(\n {},\n 'feature gates not configured, skipping initialization',\n )\n return\n }\n\n try {\n this.client = new GrowthBookClient({\n apiHost: this.config.growthBookApiHost,\n clientKey: this.config.growthBookClientKey,\n onFeatureUsage: async (feature, result, userContext) => {\n if (IGNORE_METRICS_FOR_GATES.has(feature as Gate)) return\n\n await this.metrics.track(\n 'feature:viewed',\n {\n featureId: feature,\n featureResultValue: result.value,\n experimentId: result.experiment?.key,\n variationId: result.experimentResult?.key,\n },\n parsedUserContextToTrackingMetadata(\n extractUserContextFromGrowthbookUserContext(userContext),\n ),\n )\n },\n trackingCallback: async (experiment, result, userContext) => {\n /**\n * Experiments are only fired in a feature gate has an Experiment\n * attached in Growthbook. Howerver, we want to be extra sure that a\n * misconfigured experiment doesn't result in a huge increase in events, so we\n * protect this here.\n */\n if (\n result.featureId &&\n IGNORE_METRICS_FOR_GATES.has(result.featureId as Gate)\n )\n return\n\n await this.metrics.track(\n 'experiment:viewed',\n {\n experimentId: experiment.key,\n variationId: result.key,\n },\n parsedUserContextToTrackingMetadata(\n extractUserContextFromGrowthbookUserContext(userContext),\n ),\n )\n },\n })\n\n const { source, error } = await this.client.init({\n timeout: FETCH_TIMEOUT,\n })\n\n /**\n * This does not necessarily mean that the client completely failed,\n * since it could just be that the request timed out. It may succeed\n * after the timeout, or later during refreshes.\n *\n * @see https://docs.growthbook.io/lib/node#error-handling\n */\n if (error) {\n featureGatesLogger.error(\n { err: error, source },\n 'Client failed to initialize normally',\n )\n }\n\n /**\n * Set up periodic refresh of feature definitions\n *\n * @see https://docs.growthbook.io/lib/node#refreshing-features\n */\n this.refreshInterval = setInterval(async () => {\n try {\n await this.client?.refreshFeatures({\n timeout: FETCH_TIMEOUT,\n })\n } catch (err) {\n featureGatesLogger.error({ err }, 'Failed to refresh features')\n }\n }, REFETCH_INTERVAL)\n\n /* Ready or not, here we come */\n this.ready = true\n } catch (err) {\n featureGatesLogger.error({ err }, 'Client initialization failed')\n }\n }\n\n async destroy() {\n if (this.ready) {\n this.ready = false\n if (this.refreshInterval) {\n clearInterval(this.refreshInterval)\n }\n }\n await this.metrics.stop()\n }\n\n async [Symbol.asyncDispose]() {\n await this.destroy()\n }\n\n /**\n * Evaluate multiple feature gates for a given user, returning a map of gate\n * ID to boolean result.\n */\n private checkGates(\n gates: Gate[],\n userContext: UserContext,\n ): CheckedFeatureGatesMap {\n const gb = this.client\n const attributes = normalizeUserContext(userContext)\n if (!gb || !this.ready) return new Map(gates.map((g) => [g, false]))\n return new Map(gates.map((g) => [g, gb.isOn(g, { attributes })]))\n }\n\n scope(scopedUserContext: UserContext): ScopedFeatureGatesClient {\n /*\n * Create initial deviceId and sessionId values for the scoped client, to\n * be used throughout this request lifecycle.\n */\n const base = normalizeUserContext(scopedUserContext)\n return {\n Gate: this.Gate,\n checkGates: (\n gates: Gate[],\n userContextOverrides?: Pick<UserContext, 'did'>,\n ) => {\n const userContext = mergeUserContexts(base, userContextOverrides)\n return this.checkGates(gates, userContext)\n },\n checkGate: (gate: Gate, userContextOverrides?: UserContext) => {\n const userContext = mergeUserContexts(base, userContextOverrides)\n return this.checkGates([gate], userContext).get(gate) || false\n },\n }\n }\n\n /**\n * Parse properties available in XRPC handlers to `UserContext`. The returned\n * proeprties are used as GrowthBook `attributes` as well as the metadata\n * payload for our analytics events. This ensures that the same user properties\n * are used for both feature gate targeting and analytics.\n */\n parseUserContextFromHandler({\n viewer,\n req,\n }: {\n /**\n * The user's DID\n */\n viewer: string | null\n /**\n * The express request object, used to extract analytics headers for the user context\n */\n req: express.Request\n }): UserContext {\n const deviceId = req.header(ANALYTICS_HEADER_DEVICE_ID)\n const sessionId = req.header(ANALYTICS_HEADER_SESSION_ID)\n\n return normalizeUserContext({\n did: viewer,\n deviceId,\n sessionId,\n })\n }\n}\n"]}
@@ -23,9 +23,9 @@ export declare class MetricsClient<M extends Record<string, any> = Events> {
23
23
  private flushInterval;
24
24
  constructor(config: Config);
25
25
  start(): void;
26
- stop(): void;
27
- track<E extends keyof M>(event: E, payload: M[E], metadata?: Record<string, any>): void;
28
- flush(): void;
26
+ stop(): Promise<void>;
27
+ track<E extends keyof M>(event: E, payload: M[E], metadata?: Record<string, any>): Promise<void>;
28
+ flush(): Promise<void>;
29
29
  private sendBatch;
30
30
  }
31
31
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/feature-gates/metrics.ts"],"names":[],"mappings":"AAEA,KAAK,MAAM,GAAG;IACZ,mBAAmB,EAAE;QACnB,YAAY,EAAE,MAAM,CAAA;QACpB,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;IACD,gBAAgB,EAAE;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,kBAAkB,EAAE,OAAO,CAAA;QAC3B,6DAA6D;QAC7D,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,6DAA6D;QAC7D,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,CAAA;CACF,CAAA;AASD,MAAM,MAAM,MAAM,GAAG;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,qBAAa,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM;IAMnD,OAAO,CAAC,MAAM;IAL1B,YAAY,SAAM;IAElB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,aAAa,CAA8B;IACnD,YAAoB,MAAM,EAAE,MAAM,EAAI;IAEtC,KAAK,SAMJ;IAED,IAAI,SAMH;IAED,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,EACrB,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EACb,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,QAgBnC;IAED,KAAK,SAIJ;YAEa,SAAS;CA2BxB"}
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/feature-gates/metrics.ts"],"names":[],"mappings":"AAEA,KAAK,MAAM,GAAG;IACZ,mBAAmB,EAAE;QACnB,YAAY,EAAE,MAAM,CAAA;QACpB,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;IACD,gBAAgB,EAAE;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,kBAAkB,EAAE,OAAO,CAAA;QAC3B,6DAA6D;QAC7D,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,6DAA6D;QAC7D,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,CAAA;CACF,CAAA;AASD,MAAM,MAAM,MAAM,GAAG;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,qBAAa,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM;IAMnD,OAAO,CAAC,MAAM;IAL1B,YAAY,SAAM;IAElB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,aAAa,CAA8B;IACnD,YAAoB,MAAM,EAAE,MAAM,EAAI;IAEtC,KAAK,SAMJ;IAEK,IAAI,kBAMT;IAEK,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,EAC3B,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EACb,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,iBAgBnC;IAEK,KAAK,kBAIV;YAEa,SAAS;CA2BxB"}
@@ -12,18 +12,18 @@ export class MetricsClient {
12
12
  return;
13
13
  this.started = true;
14
14
  this.flushInterval = setInterval(() => {
15
- this.flush();
15
+ void this.flush();
16
16
  }, 10_000);
17
17
  }
18
- stop() {
18
+ async stop() {
19
19
  if (this.flushInterval) {
20
20
  clearInterval(this.flushInterval);
21
21
  this.flushInterval = null;
22
22
  }
23
- this.flush();
23
+ await this.flush();
24
24
  }
25
- track(event, payload, metadata = {}) {
26
- this.start();
25
+ async track(event, payload, metadata = {}) {
26
+ await this.start();
27
27
  const e = {
28
28
  source: 'appview',
29
29
  time: Date.now(),
@@ -33,14 +33,14 @@ export class MetricsClient {
33
33
  };
34
34
  this.queue.push(e);
35
35
  if (this.queue.length > this.maxBatchSize) {
36
- this.flush();
36
+ await this.flush();
37
37
  }
38
38
  }
39
- flush() {
39
+ async flush() {
40
40
  if (!this.queue.length)
41
41
  return;
42
42
  const events = this.queue.splice(0, this.queue.length);
43
- this.sendBatch(events);
43
+ await this.sendBatch(events);
44
44
  }
45
45
  async sendBatch(events) {
46
46
  if (!this.config.trackingEndpoint)
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/feature-gates/metrics.ts"],"names":[],"mappings":"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","sourcesContent":["import { featureGatesLogger } from '../logger.js'\n\ntype Events = {\n 'experiment:viewed': {\n experimentId: string\n variationId: string\n }\n 'feature:viewed': {\n featureId: string\n featureResultValue: unknown\n /** Only available if feature has experiment rules applied */\n experimentId?: string\n /** Only available if feature has experiment rules applied */\n variationId?: string\n }\n}\n\ntype Event<M extends Record<string, any>> = {\n time: number\n event: keyof M\n payload: M[keyof M]\n metadata: Record<string, any>\n}\n\nexport type Config = {\n trackingEndpoint?: string\n}\n\nexport class MetricsClient<M extends Record<string, any> = Events> {\n maxBatchSize = 100\n\n private started: boolean = false\n private queue: Event<M>[] = []\n private flushInterval: NodeJS.Timeout | null = null\n constructor(private config: Config) {}\n\n start() {\n if (this.started) return\n this.started = true\n this.flushInterval = setInterval(() => {\n this.flush()\n }, 10_000)\n }\n\n stop() {\n if (this.flushInterval) {\n clearInterval(this.flushInterval)\n this.flushInterval = null\n }\n this.flush()\n }\n\n track<E extends keyof M>(\n event: E,\n payload: M[E],\n metadata: Record<string, any> = {},\n ) {\n this.start()\n\n const e = {\n source: 'appview',\n time: Date.now(),\n event,\n payload,\n metadata,\n }\n this.queue.push(e)\n\n if (this.queue.length > this.maxBatchSize) {\n this.flush()\n }\n }\n\n flush() {\n if (!this.queue.length) return\n const events = this.queue.splice(0, this.queue.length)\n this.sendBatch(events)\n }\n\n private async sendBatch(events: Event<M>[]) {\n if (!this.config.trackingEndpoint) return\n\n try {\n const res = await fetch(this.config.trackingEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ events }),\n keepalive: true,\n })\n\n if (!res.ok) {\n const errorText = await res.text().catch(() => 'Unknown error')\n featureGatesLogger.error(\n { err: new Error(`${res.status} Failed to fetch - ${errorText}`) },\n 'Failed to send metrics',\n )\n } else {\n // Drain response body to allow connection reuse.\n await res.text().catch(() => {})\n }\n } catch (err) {\n featureGatesLogger.error({ err }, 'Failed to send metrics')\n }\n }\n}\n"]}
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/feature-gates/metrics.ts"],"names":[],"mappings":"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","sourcesContent":["import { featureGatesLogger } from '../logger.js'\n\ntype Events = {\n 'experiment:viewed': {\n experimentId: string\n variationId: string\n }\n 'feature:viewed': {\n featureId: string\n featureResultValue: unknown\n /** Only available if feature has experiment rules applied */\n experimentId?: string\n /** Only available if feature has experiment rules applied */\n variationId?: string\n }\n}\n\ntype Event<M extends Record<string, any>> = {\n time: number\n event: keyof M\n payload: M[keyof M]\n metadata: Record<string, any>\n}\n\nexport type Config = {\n trackingEndpoint?: string\n}\n\nexport class MetricsClient<M extends Record<string, any> = Events> {\n maxBatchSize = 100\n\n private started: boolean = false\n private queue: Event<M>[] = []\n private flushInterval: NodeJS.Timeout | null = null\n constructor(private config: Config) {}\n\n start() {\n if (this.started) return\n this.started = true\n this.flushInterval = setInterval(() => {\n void this.flush()\n }, 10_000)\n }\n\n async stop() {\n if (this.flushInterval) {\n clearInterval(this.flushInterval)\n this.flushInterval = null\n }\n await this.flush()\n }\n\n async track<E extends keyof M>(\n event: E,\n payload: M[E],\n metadata: Record<string, any> = {},\n ) {\n await this.start()\n\n const e = {\n source: 'appview',\n time: Date.now(),\n event,\n payload,\n metadata,\n }\n this.queue.push(e)\n\n if (this.queue.length > this.maxBatchSize) {\n await this.flush()\n }\n }\n\n async flush() {\n if (!this.queue.length) return\n const events = this.queue.splice(0, this.queue.length)\n await this.sendBatch(events)\n }\n\n private async sendBatch(events: Event<M>[]) {\n if (!this.config.trackingEndpoint) return\n\n try {\n const res = await fetch(this.config.trackingEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ events }),\n keepalive: true,\n })\n\n if (!res.ok) {\n const errorText = await res.text().catch(() => 'Unknown error')\n featureGatesLogger.error(\n { err: new Error(`${res.status} Failed to fetch - ${errorText}`) },\n 'Failed to send metrics',\n )\n } else {\n // Drain response body to allow connection reuse.\n await res.text().catch(() => {})\n }\n } catch (err) {\n featureGatesLogger.error({ err }, 'Failed to send metrics')\n }\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -25,6 +25,7 @@ export declare class BskyAppView {
25
25
  }): BskyAppView;
26
26
  start(): Promise<http.Server>;
27
27
  destroy(): Promise<void>;
28
+ [Symbol.asyncDispose](): Promise<void>;
28
29
  }
29
30
  export default BskyAppView;
30
31
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,WAAW,CAAA;AAK5B,OAAO,OAAO,MAAM,SAAS,CAAA;AAO7B,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAczC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAyBzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAA;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElC,qBAAa,WAAW;IACf,GAAG,EAAE,UAAU,CAAA;IACf,GAAG,EAAE,OAAO,CAAC,WAAW,CAAA;IACxB,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAA;IAC3B,OAAO,CAAC,UAAU,CAAC,CAAgB;IAEnC,YAAY,IAAI,EAAE;QAAE,GAAG,EAAE,UAAU,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC,WAAW,CAAA;KAAE,EAG9D;IAED,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;QAClB,MAAM,EAAE,YAAY,CAAA;QACpB,UAAU,EAAE,OAAO,CAAA;KACpB,GAAG,WAAW,CA6Md;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAalC;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAI7B;CACF;eAEc,WAAW"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,WAAW,CAAA;AAK5B,OAAO,OAAO,MAAM,SAAS,CAAA;AAI7B,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAczC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAyBzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAA;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElC,qBAAa,WAAW;IACf,GAAG,EAAE,UAAU,CAAA;IACf,GAAG,EAAE,OAAO,CAAC,WAAW,CAAA;IACxB,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAA;IAC3B,OAAO,CAAC,UAAU,CAAC,CAA+B;IAElD,YAAY,IAAI,EAAE;QAAE,GAAG,EAAE,UAAU,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC,WAAW,CAAA;KAAE,EAG9D;IAED,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;QAClB,MAAM,EAAE,YAAY,CAAA;QACpB,UAAU,EAAE,OAAO,CAAA;KACpB,GAAG,WAAW,CA6Md;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAalC;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAU7B;IAEK,CAAC,MAAM,CAAC,YAAY,CAAC,kBAE1B;CACF;eAEc,WAAW"}
package/dist/index.js CHANGED
@@ -3,10 +3,8 @@ import compression from 'compression';
3
3
  import cors from 'cors';
4
4
  import { Etcd3 } from 'etcd3';
5
5
  import express from 'express';
6
- // eslint-disable-next-line import/default, import/no-named-as-default-member
6
+ // eslint-disable-next-line import/default
7
7
  import httpTerminator from 'http-terminator';
8
- // eslint-disable-next-line import/no-named-as-default-member
9
- const { createHttpTerminator } = httpTerminator;
10
8
  import { DAY, SECOND } from '@atproto/common';
11
9
  import { IdResolver } from '@atproto/identity';
12
10
  import { Client } from '@atproto/lex';
@@ -214,16 +212,27 @@ export class BskyAppView {
214
212
  const server = this.app.listen(this.ctx.cfg.port);
215
213
  this.server = server;
216
214
  server.keepAliveTimeout = 90000;
217
- this.terminator = createHttpTerminator({ server });
215
+ this.terminator = httpTerminator.createHttpTerminator({ server });
218
216
  await events.once(server, 'listening');
219
217
  const { port } = server.address();
220
218
  this.ctx.cfg.assignPort(port);
221
219
  return server;
222
220
  }
223
221
  async destroy() {
224
- this.ctx.featureGatesClient.destroy();
225
- await this.terminator?.terminate();
226
- await this.ctx.etcd?.close();
222
+ try {
223
+ await this.ctx.featureGatesClient.destroy();
224
+ }
225
+ finally {
226
+ try {
227
+ await this.terminator?.terminate();
228
+ }
229
+ finally {
230
+ await this.ctx.etcd?.close();
231
+ }
232
+ }
233
+ }
234
+ async [Symbol.asyncDispose]() {
235
+ await this.destroy();
227
236
  }
228
237
  }
229
238
  export default BskyAppView;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import events from 'node:events'\nimport http from 'node:http'\nimport { AddressInfo } from 'node:net'\nimport compression from 'compression'\nimport cors from 'cors'\nimport { Etcd3 } from 'etcd3'\nimport express from 'express'\n// eslint-disable-next-line import/default, import/no-named-as-default-member\nimport httpTerminator from 'http-terminator'\n// eslint-disable-next-line import/no-named-as-default-member\nconst { createHttpTerminator } = httpTerminator\ntype HttpTerminator = ReturnType<typeof createHttpTerminator>\nimport { DAY, SECOND } from '@atproto/common'\nimport { Keypair } from '@atproto/crypto'\nimport { IdResolver } from '@atproto/identity'\nimport { Client } from '@atproto/lex'\nimport { createServer } from '@atproto/xrpc-server'\nimport { createBlobDispatcher } from './api/blob-dispatcher.js'\nimport API, {\n blobResolver,\n external,\n health,\n sitemap,\n wellKnown,\n} from './api/index.js'\nimport { AuthVerifier, createPublicKeyObject } from './auth-verifier.js'\nimport { authWithApiKey as bsyncAuth, createBsyncClient } from './bsync.js'\nimport { ServerConfig } from './config.js'\nimport { AppContext } from './context.js'\nimport {\n authWithApiKey as courierAuth,\n createCourierClient,\n} from './courier.js'\nimport {\n BasicHostList,\n EtcdHostList,\n createDataPlaneClient,\n} from './data-plane/client/index.js'\nimport * as error from './error.js'\nimport { FeatureGatesClient } from './feature-gates/index.js'\nimport { Hydrator } from './hydration/hydrator.js'\nimport * as imageServer from './image/server.js'\nimport { ImageUriBuilder } from './image/uri.js'\nimport { createKwsClient } from './kws.js'\nimport { loggerMiddleware } from './logger.js'\nimport {\n authWithApiKey as rolodexAuth,\n createRolodexClient,\n} from './rolodex.js'\nimport { createStashClient } from './stash.js'\nimport { Views } from './views/index.js'\nimport { VideoUriBuilder } from './views/util.js'\n\nexport { ServerConfig } from './config.js'\nexport type { ServerConfigValues } from './config.js'\nexport { AppContext } from './context.js'\nexport * from './data-plane/index.js'\nexport { BackgroundQueue } from './data-plane/server/background.js'\nexport { Database } from './data-plane/server/db/index.js'\nexport { Redis } from './redis.js'\n\nexport class BskyAppView {\n public ctx: AppContext\n public app: express.Application\n public server?: http.Server\n private terminator?: HttpTerminator\n\n constructor(opts: { ctx: AppContext; app: express.Application }) {\n this.ctx = opts.ctx\n this.app = opts.app\n }\n\n static create(opts: {\n config: ServerConfig\n signingKey: Keypair\n }): BskyAppView {\n const { config, signingKey } = opts\n const app = express()\n app.set('trust proxy', true)\n app.use(cors({ maxAge: DAY / SECOND }))\n app.use(loggerMiddleware)\n app.use(compression())\n\n // used solely for handle resolution: identity lookups occur on dataplane\n const idResolver = new IdResolver({\n plcUrl: config.didPlcUrl,\n backupNameservers: config.handleResolveNameservers,\n })\n\n const imgUriBuilderUrl =\n config.cdnUrl ||\n (config.publicUrl ? `${config.publicUrl}/img` : undefined)\n if (!imgUriBuilderUrl) {\n throw new Error('No image URI builder URL could be determined')\n }\n const imgUriBuilder = new ImageUriBuilder(imgUriBuilderUrl)\n const videoUriBuilder = new VideoUriBuilder({\n playlistUrlPattern:\n config.videoPlaylistUrlPattern ||\n `${config.publicUrl}/vid/%s/%s/playlist.m3u8`,\n thumbnailUrlPattern:\n config.videoThumbnailUrlPattern ||\n `${config.publicUrl}/vid/%s/%s/thumbnail.jpg`,\n })\n\n const searchClient = config.searchUrl\n ? new Client(\n {\n service: config.searchUrl,\n },\n {\n // Trust internal services to send us well-formed responses\n strictResponseProcessing: false,\n validateResponse: config.debugMode,\n },\n )\n : undefined\n\n const suggestionsClient = config.suggestionsUrl\n ? new Client(\n {\n service: config.suggestionsUrl,\n headers: config.suggestionsApiKey\n ? { authorization: `Bearer ${config.suggestionsApiKey}` }\n : undefined,\n },\n {\n // Trust internal services to send us well-formed responses\n strictResponseProcessing: false,\n validateResponse: config.debugMode,\n },\n )\n : undefined\n\n const topicsClient = config.topicsUrl\n ? new Client(\n {\n service: config.topicsUrl,\n headers: config.topicsApiKey\n ? { authorization: `Bearer ${config.topicsApiKey}` }\n : undefined,\n },\n {\n // Trust internal services to send us well-formed responses\n strictResponseProcessing: false,\n validateResponse: config.debugMode,\n },\n )\n : undefined\n\n const etcd = config.etcdHosts.length\n ? new Etcd3({ hosts: config.etcdHosts })\n : undefined\n\n const dataplaneHostList =\n etcd && config.dataplaneUrlsEtcdKeyPrefix\n ? new EtcdHostList(\n etcd,\n config.dataplaneUrlsEtcdKeyPrefix,\n config.dataplaneUrls,\n )\n : new BasicHostList(config.dataplaneUrls)\n\n const featureGatesClient = new FeatureGatesClient({\n growthBookApiHost: config.growthBookApiHost,\n growthBookClientKey: config.growthBookClientKey,\n eventProxyTrackingEndpoint: config.eventProxyTrackingEndpoint,\n })\n\n const dataplane = createDataPlaneClient(dataplaneHostList, {\n httpVersion: config.dataplaneHttpVersion,\n rejectUnauthorized: !config.dataplaneIgnoreBadTls,\n })\n const hydrator = new Hydrator(dataplane, config.labelsFromIssuerDids, {\n debugFieldAllowedDids: config.debugFieldAllowedDids,\n featureGatesClient,\n })\n const views = new Views({\n imgUriBuilder: imgUriBuilder,\n videoUriBuilder: videoUriBuilder,\n indexedAtEpoch: config.indexedAtEpoch,\n threadTagsBumpDown: [...config.threadTagsBumpDown],\n threadTagsHide: [...config.threadTagsHide],\n visibilityTagHide: config.visibilityTagHide,\n visibilityTagRankPrefix: config.visibilityTagRankPrefix,\n })\n\n const bsyncClient = createBsyncClient({\n baseUrl: config.bsyncUrl,\n httpVersion: config.bsyncHttpVersion ?? '2',\n nodeOptions: { rejectUnauthorized: !config.bsyncIgnoreBadTls },\n interceptors: config.bsyncApiKey ? [bsyncAuth(config.bsyncApiKey)] : [],\n })\n\n const stashClient = createStashClient(bsyncClient)\n\n const courierClient = config.courierUrl\n ? createCourierClient({\n baseUrl: config.courierUrl,\n httpVersion: config.courierHttpVersion ?? '2',\n nodeOptions: { rejectUnauthorized: !config.courierIgnoreBadTls },\n interceptors: config.courierApiKey\n ? [courierAuth(config.courierApiKey)]\n : [],\n })\n : undefined\n\n const rolodexClient = config.rolodexUrl\n ? createRolodexClient({\n baseUrl: config.rolodexUrl,\n httpVersion: config.rolodexHttpVersion ?? '2',\n nodeOptions: { rejectUnauthorized: !config.rolodexIgnoreBadTls },\n interceptors: config.rolodexApiKey\n ? [rolodexAuth(config.rolodexApiKey)]\n : [],\n })\n : undefined\n\n const kwsClient = config.kws ? createKwsClient(config.kws) : undefined\n\n const entrywayJwtPublicKey = config.entrywayJwtPublicKeyHex\n ? createPublicKeyObject(config.entrywayJwtPublicKeyHex)\n : undefined\n const authVerifier = new AuthVerifier(dataplane, {\n ownDid: config.serverDid,\n alternateAudienceDids: config.alternateAudienceDids,\n modServiceDid: config.modServiceDid,\n adminPasses: config.adminPasswords,\n entrywayJwtPublicKey,\n })\n\n const blobDispatcher = createBlobDispatcher(config)\n\n const ctx = new AppContext({\n cfg: config,\n etcd,\n dataplane,\n dataplaneHostList,\n searchClient,\n suggestionsClient,\n topicsClient,\n hydrator,\n views,\n signingKey,\n idResolver,\n bsyncClient,\n stashClient,\n courierClient,\n rolodexClient,\n authVerifier,\n featureGatesClient,\n blobDispatcher,\n kwsClient,\n })\n\n const server = createServer([], {\n validateResponse: config.debugMode,\n payload: {\n jsonLimit: 100 * 1024, // 100kb\n textLimit: 100 * 1024, // 100kb\n blobLimit: 5 * 1024 * 1024, // 5mb\n },\n })\n\n API(server, ctx)\n\n app.use(health.createRouter(ctx))\n app.use(wellKnown.createRouter(ctx))\n app.use(blobResolver.createMiddleware(ctx))\n app.use(imageServer.createMiddleware(ctx, { prefix: '/img/' }))\n\n if (config.dataplaneUrls.length > 0 || config.dataplaneUrlsEtcdKeyPrefix) {\n app.use(sitemap.createRouter(ctx))\n }\n\n app.use(server.router)\n app.use(error.handler)\n app.use('/external', external.createRouter(ctx))\n\n return new BskyAppView({ ctx, app })\n }\n\n async start(): Promise<http.Server> {\n if (this.ctx.dataplaneHostList instanceof EtcdHostList) {\n await this.ctx.dataplaneHostList.connect()\n }\n this.ctx.featureGatesClient.start() // lazy, no await\n const server = this.app.listen(this.ctx.cfg.port)\n this.server = server\n server.keepAliveTimeout = 90000\n this.terminator = createHttpTerminator({ server })\n await events.once(server, 'listening')\n const { port } = server.address() as AddressInfo\n this.ctx.cfg.assignPort(port)\n return server\n }\n\n async destroy(): Promise<void> {\n this.ctx.featureGatesClient.destroy()\n await this.terminator?.terminate()\n await this.ctx.etcd?.close()\n }\n}\n\nexport default BskyAppView\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAA;AAGhC,OAAO,WAAW,MAAM,aAAa,CAAA;AACrC,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAC7B,OAAO,OAAO,MAAM,SAAS,CAAA;AAC7B,0CAA0C;AAC1C,OAAO,cAAc,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAA;AAC/D,OAAO,GAAG,EAAE,EACV,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,OAAO,EACP,SAAS,GACV,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,EAAE,cAAc,IAAI,SAAS,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE3E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EACL,cAAc,IAAI,WAAW,EAC7B,mBAAmB,GACpB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,qBAAqB,GACtB,MAAM,8BAA8B,CAAA;AACrC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClD,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EACL,cAAc,IAAI,WAAW,EAC7B,mBAAmB,GACpB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEjD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAA;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAElC,MAAM,OAAO,WAAW;IAMtB,YAAY,IAAmD;QAC7D,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAA;QACnB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAA;IACrB,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,IAGb;QACC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAA;QACnC,MAAM,GAAG,GAAG,OAAO,EAAE,CAAA;QACrB,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,CAAA;QAC5B,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,GAAG,MAAM,EAAE,CAAC,CAAC,CAAA;QACvC,GAAG,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;QACzB,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAA;QAEtB,yEAAyE;QACzE,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC;YAChC,MAAM,EAAE,MAAM,CAAC,SAAS;YACxB,iBAAiB,EAAE,MAAM,CAAC,wBAAwB;SACnD,CAAC,CAAA;QAEF,MAAM,gBAAgB,GACpB,MAAM,CAAC,MAAM;YACb,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;QAC5D,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAA;QACjE,CAAC;QACD,MAAM,aAAa,GAAG,IAAI,eAAe,CAAC,gBAAgB,CAAC,CAAA;QAC3D,MAAM,eAAe,GAAG,IAAI,eAAe,CAAC;YAC1C,kBAAkB,EAChB,MAAM,CAAC,uBAAuB;gBAC9B,GAAG,MAAM,CAAC,SAAS,0BAA0B;YAC/C,mBAAmB,EACjB,MAAM,CAAC,wBAAwB;gBAC/B,GAAG,MAAM,CAAC,SAAS,0BAA0B;SAChD,CAAC,CAAA;QAEF,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS;YACnC,CAAC,CAAC,IAAI,MAAM,CACR;gBACE,OAAO,EAAE,MAAM,CAAC,SAAS;aAC1B,EACD;gBACE,2DAA2D;gBAC3D,wBAAwB,EAAE,KAAK;gBAC/B,gBAAgB,EAAE,MAAM,CAAC,SAAS;aACnC,CACF;YACH,CAAC,CAAC,SAAS,CAAA;QAEb,MAAM,iBAAiB,GAAG,MAAM,CAAC,cAAc;YAC7C,CAAC,CAAC,IAAI,MAAM,CACR;gBACE,OAAO,EAAE,MAAM,CAAC,cAAc;gBAC9B,OAAO,EAAE,MAAM,CAAC,iBAAiB;oBAC/B,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,MAAM,CAAC,iBAAiB,EAAE,EAAE;oBACzD,CAAC,CAAC,SAAS;aACd,EACD;gBACE,2DAA2D;gBAC3D,wBAAwB,EAAE,KAAK;gBAC/B,gBAAgB,EAAE,MAAM,CAAC,SAAS;aACnC,CACF;YACH,CAAC,CAAC,SAAS,CAAA;QAEb,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS;YACnC,CAAC,CAAC,IAAI,MAAM,CACR;gBACE,OAAO,EAAE,MAAM,CAAC,SAAS;gBACzB,OAAO,EAAE,MAAM,CAAC,YAAY;oBAC1B,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,MAAM,CAAC,YAAY,EAAE,EAAE;oBACpD,CAAC,CAAC,SAAS;aACd,EACD;gBACE,2DAA2D;gBAC3D,wBAAwB,EAAE,KAAK;gBAC/B,gBAAgB,EAAE,MAAM,CAAC,SAAS;aACnC,CACF;YACH,CAAC,CAAC,SAAS,CAAA;QAEb,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM;YAClC,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;YACxC,CAAC,CAAC,SAAS,CAAA;QAEb,MAAM,iBAAiB,GACrB,IAAI,IAAI,MAAM,CAAC,0BAA0B;YACvC,CAAC,CAAC,IAAI,YAAY,CACd,IAAI,EACJ,MAAM,CAAC,0BAA0B,EACjC,MAAM,CAAC,aAAa,CACrB;YACH,CAAC,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,aAAa,CAAC,CAAA;QAE7C,MAAM,kBAAkB,GAAG,IAAI,kBAAkB,CAAC;YAChD,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;YAC3C,mBAAmB,EAAE,MAAM,CAAC,mBAAmB;YAC/C,0BAA0B,EAAE,MAAM,CAAC,0BAA0B;SAC9D,CAAC,CAAA;QAEF,MAAM,SAAS,GAAG,qBAAqB,CAAC,iBAAiB,EAAE;YACzD,WAAW,EAAE,MAAM,CAAC,oBAAoB;YACxC,kBAAkB,EAAE,CAAC,MAAM,CAAC,qBAAqB;SAClD,CAAC,CAAA;QACF,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,oBAAoB,EAAE;YACpE,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;YACnD,kBAAkB;SACnB,CAAC,CAAA;QACF,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;YACtB,aAAa,EAAE,aAAa;YAC5B,eAAe,EAAE,eAAe;YAChC,cAAc,EAAE,MAAM,CAAC,cAAc;YACrC,kBAAkB,EAAE,CAAC,GAAG,MAAM,CAAC,kBAAkB,CAAC;YAClD,cAAc,EAAE,CAAC,GAAG,MAAM,CAAC,cAAc,CAAC;YAC1C,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;YAC3C,uBAAuB,EAAE,MAAM,CAAC,uBAAuB;SACxD,CAAC,CAAA;QAEF,MAAM,WAAW,GAAG,iBAAiB,CAAC;YACpC,OAAO,EAAE,MAAM,CAAC,QAAQ;YACxB,WAAW,EAAE,MAAM,CAAC,gBAAgB,IAAI,GAAG;YAC3C,WAAW,EAAE,EAAE,kBAAkB,EAAE,CAAC,MAAM,CAAC,iBAAiB,EAAE;YAC9D,YAAY,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;SACxE,CAAC,CAAA;QAEF,MAAM,WAAW,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAA;QAElD,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU;YACrC,CAAC,CAAC,mBAAmB,CAAC;gBAClB,OAAO,EAAE,MAAM,CAAC,UAAU;gBAC1B,WAAW,EAAE,MAAM,CAAC,kBAAkB,IAAI,GAAG;gBAC7C,WAAW,EAAE,EAAE,kBAAkB,EAAE,CAAC,MAAM,CAAC,mBAAmB,EAAE;gBAChE,YAAY,EAAE,MAAM,CAAC,aAAa;oBAChC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;oBACrC,CAAC,CAAC,EAAE;aACP,CAAC;YACJ,CAAC,CAAC,SAAS,CAAA;QAEb,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU;YACrC,CAAC,CAAC,mBAAmB,CAAC;gBAClB,OAAO,EAAE,MAAM,CAAC,UAAU;gBAC1B,WAAW,EAAE,MAAM,CAAC,kBAAkB,IAAI,GAAG;gBAC7C,WAAW,EAAE,EAAE,kBAAkB,EAAE,CAAC,MAAM,CAAC,mBAAmB,EAAE;gBAChE,YAAY,EAAE,MAAM,CAAC,aAAa;oBAChC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;oBACrC,CAAC,CAAC,EAAE;aACP,CAAC;YACJ,CAAC,CAAC,SAAS,CAAA;QAEb,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAEtE,MAAM,oBAAoB,GAAG,MAAM,CAAC,uBAAuB;YACzD,CAAC,CAAC,qBAAqB,CAAC,MAAM,CAAC,uBAAuB,CAAC;YACvD,CAAC,CAAC,SAAS,CAAA;QACb,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,SAAS,EAAE;YAC/C,MAAM,EAAE,MAAM,CAAC,SAAS;YACxB,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;YACnD,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,WAAW,EAAE,MAAM,CAAC,cAAc;YAClC,oBAAoB;SACrB,CAAC,CAAA;QAEF,MAAM,cAAc,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAA;QAEnD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC;YACzB,GAAG,EAAE,MAAM;YACX,IAAI;YACJ,SAAS;YACT,iBAAiB;YACjB,YAAY;YACZ,iBAAiB;YACjB,YAAY;YACZ,QAAQ;YACR,KAAK;YACL,UAAU;YACV,UAAU;YACV,WAAW;YACX,WAAW;YACX,aAAa;YACb,aAAa;YACb,YAAY;YACZ,kBAAkB;YAClB,cAAc;YACd,SAAS;SACV,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,EAAE;YAC9B,gBAAgB,EAAE,MAAM,CAAC,SAAS;YAClC,OAAO,EAAE;gBACP,SAAS,EAAE,GAAG,GAAG,IAAI,EAAE,QAAQ;gBAC/B,SAAS,EAAE,GAAG,GAAG,IAAI,EAAE,QAAQ;gBAC/B,SAAS,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,MAAM;aACnC;SACF,CAAC,CAAA;QAEF,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAEhB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAA;QACjC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAA;QACpC,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAA;QAC3C,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,gBAAgB,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAA;QAE/D,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,0BAA0B,EAAE,CAAC;YACzE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAA;QACpC,CAAC;QAED,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QACtB,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACtB,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAA;QAEhD,OAAO,IAAI,WAAW,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAA;IACtC,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,GAAG,CAAC,iBAAiB,YAAY,YAAY,EAAE,CAAC;YACvD,MAAM,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,OAAO,EAAE,CAAA;QAC5C,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAA,CAAC,iBAAiB;QACrD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACjD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,MAAM,CAAC,gBAAgB,GAAG,KAAK,CAAA;QAC/B,IAAI,CAAC,UAAU,GAAG,cAAc,CAAC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;QACjE,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;QACtC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,OAAO,EAAiB,CAAA;QAChD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QAC7B,OAAO,MAAM,CAAA;IACf,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,OAAO,EAAE,CAAA;QAC7C,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,CAAA;YACpC,CAAC;oBAAS,CAAC;gBACT,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAA;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;QACzB,MAAM,IAAI,CAAC,OAAO,EAAE,CAAA;IACtB,CAAC;CACF;AAED,eAAe,WAAW,CAAA","sourcesContent":["import events from 'node:events'\nimport http from 'node:http'\nimport { AddressInfo } from 'node:net'\nimport compression from 'compression'\nimport cors from 'cors'\nimport { Etcd3 } from 'etcd3'\nimport express from 'express'\n// eslint-disable-next-line import/default\nimport httpTerminator from 'http-terminator'\nimport { DAY, SECOND } from '@atproto/common'\nimport { Keypair } from '@atproto/crypto'\nimport { IdResolver } from '@atproto/identity'\nimport { Client } from '@atproto/lex'\nimport { createServer } from '@atproto/xrpc-server'\nimport { createBlobDispatcher } from './api/blob-dispatcher.js'\nimport API, {\n blobResolver,\n external,\n health,\n sitemap,\n wellKnown,\n} from './api/index.js'\nimport { AuthVerifier, createPublicKeyObject } from './auth-verifier.js'\nimport { authWithApiKey as bsyncAuth, createBsyncClient } from './bsync.js'\nimport { ServerConfig } from './config.js'\nimport { AppContext } from './context.js'\nimport {\n authWithApiKey as courierAuth,\n createCourierClient,\n} from './courier.js'\nimport {\n BasicHostList,\n EtcdHostList,\n createDataPlaneClient,\n} from './data-plane/client/index.js'\nimport * as error from './error.js'\nimport { FeatureGatesClient } from './feature-gates/index.js'\nimport { Hydrator } from './hydration/hydrator.js'\nimport * as imageServer from './image/server.js'\nimport { ImageUriBuilder } from './image/uri.js'\nimport { createKwsClient } from './kws.js'\nimport { loggerMiddleware } from './logger.js'\nimport {\n authWithApiKey as rolodexAuth,\n createRolodexClient,\n} from './rolodex.js'\nimport { createStashClient } from './stash.js'\nimport { Views } from './views/index.js'\nimport { VideoUriBuilder } from './views/util.js'\n\nexport { ServerConfig } from './config.js'\nexport type { ServerConfigValues } from './config.js'\nexport { AppContext } from './context.js'\nexport * from './data-plane/index.js'\nexport { BackgroundQueue } from './data-plane/server/background.js'\nexport { Database } from './data-plane/server/db/index.js'\nexport { Redis } from './redis.js'\n\nexport class BskyAppView {\n public ctx: AppContext\n public app: express.Application\n public server?: http.Server\n private terminator?: httpTerminator.HttpTerminator\n\n constructor(opts: { ctx: AppContext; app: express.Application }) {\n this.ctx = opts.ctx\n this.app = opts.app\n }\n\n static create(opts: {\n config: ServerConfig\n signingKey: Keypair\n }): BskyAppView {\n const { config, signingKey } = opts\n const app = express()\n app.set('trust proxy', true)\n app.use(cors({ maxAge: DAY / SECOND }))\n app.use(loggerMiddleware)\n app.use(compression())\n\n // used solely for handle resolution: identity lookups occur on dataplane\n const idResolver = new IdResolver({\n plcUrl: config.didPlcUrl,\n backupNameservers: config.handleResolveNameservers,\n })\n\n const imgUriBuilderUrl =\n config.cdnUrl ||\n (config.publicUrl ? `${config.publicUrl}/img` : undefined)\n if (!imgUriBuilderUrl) {\n throw new Error('No image URI builder URL could be determined')\n }\n const imgUriBuilder = new ImageUriBuilder(imgUriBuilderUrl)\n const videoUriBuilder = new VideoUriBuilder({\n playlistUrlPattern:\n config.videoPlaylistUrlPattern ||\n `${config.publicUrl}/vid/%s/%s/playlist.m3u8`,\n thumbnailUrlPattern:\n config.videoThumbnailUrlPattern ||\n `${config.publicUrl}/vid/%s/%s/thumbnail.jpg`,\n })\n\n const searchClient = config.searchUrl\n ? new Client(\n {\n service: config.searchUrl,\n },\n {\n // Trust internal services to send us well-formed responses\n strictResponseProcessing: false,\n validateResponse: config.debugMode,\n },\n )\n : undefined\n\n const suggestionsClient = config.suggestionsUrl\n ? new Client(\n {\n service: config.suggestionsUrl,\n headers: config.suggestionsApiKey\n ? { authorization: `Bearer ${config.suggestionsApiKey}` }\n : undefined,\n },\n {\n // Trust internal services to send us well-formed responses\n strictResponseProcessing: false,\n validateResponse: config.debugMode,\n },\n )\n : undefined\n\n const topicsClient = config.topicsUrl\n ? new Client(\n {\n service: config.topicsUrl,\n headers: config.topicsApiKey\n ? { authorization: `Bearer ${config.topicsApiKey}` }\n : undefined,\n },\n {\n // Trust internal services to send us well-formed responses\n strictResponseProcessing: false,\n validateResponse: config.debugMode,\n },\n )\n : undefined\n\n const etcd = config.etcdHosts.length\n ? new Etcd3({ hosts: config.etcdHosts })\n : undefined\n\n const dataplaneHostList =\n etcd && config.dataplaneUrlsEtcdKeyPrefix\n ? new EtcdHostList(\n etcd,\n config.dataplaneUrlsEtcdKeyPrefix,\n config.dataplaneUrls,\n )\n : new BasicHostList(config.dataplaneUrls)\n\n const featureGatesClient = new FeatureGatesClient({\n growthBookApiHost: config.growthBookApiHost,\n growthBookClientKey: config.growthBookClientKey,\n eventProxyTrackingEndpoint: config.eventProxyTrackingEndpoint,\n })\n\n const dataplane = createDataPlaneClient(dataplaneHostList, {\n httpVersion: config.dataplaneHttpVersion,\n rejectUnauthorized: !config.dataplaneIgnoreBadTls,\n })\n const hydrator = new Hydrator(dataplane, config.labelsFromIssuerDids, {\n debugFieldAllowedDids: config.debugFieldAllowedDids,\n featureGatesClient,\n })\n const views = new Views({\n imgUriBuilder: imgUriBuilder,\n videoUriBuilder: videoUriBuilder,\n indexedAtEpoch: config.indexedAtEpoch,\n threadTagsBumpDown: [...config.threadTagsBumpDown],\n threadTagsHide: [...config.threadTagsHide],\n visibilityTagHide: config.visibilityTagHide,\n visibilityTagRankPrefix: config.visibilityTagRankPrefix,\n })\n\n const bsyncClient = createBsyncClient({\n baseUrl: config.bsyncUrl,\n httpVersion: config.bsyncHttpVersion ?? '2',\n nodeOptions: { rejectUnauthorized: !config.bsyncIgnoreBadTls },\n interceptors: config.bsyncApiKey ? [bsyncAuth(config.bsyncApiKey)] : [],\n })\n\n const stashClient = createStashClient(bsyncClient)\n\n const courierClient = config.courierUrl\n ? createCourierClient({\n baseUrl: config.courierUrl,\n httpVersion: config.courierHttpVersion ?? '2',\n nodeOptions: { rejectUnauthorized: !config.courierIgnoreBadTls },\n interceptors: config.courierApiKey\n ? [courierAuth(config.courierApiKey)]\n : [],\n })\n : undefined\n\n const rolodexClient = config.rolodexUrl\n ? createRolodexClient({\n baseUrl: config.rolodexUrl,\n httpVersion: config.rolodexHttpVersion ?? '2',\n nodeOptions: { rejectUnauthorized: !config.rolodexIgnoreBadTls },\n interceptors: config.rolodexApiKey\n ? [rolodexAuth(config.rolodexApiKey)]\n : [],\n })\n : undefined\n\n const kwsClient = config.kws ? createKwsClient(config.kws) : undefined\n\n const entrywayJwtPublicKey = config.entrywayJwtPublicKeyHex\n ? createPublicKeyObject(config.entrywayJwtPublicKeyHex)\n : undefined\n const authVerifier = new AuthVerifier(dataplane, {\n ownDid: config.serverDid,\n alternateAudienceDids: config.alternateAudienceDids,\n modServiceDid: config.modServiceDid,\n adminPasses: config.adminPasswords,\n entrywayJwtPublicKey,\n })\n\n const blobDispatcher = createBlobDispatcher(config)\n\n const ctx = new AppContext({\n cfg: config,\n etcd,\n dataplane,\n dataplaneHostList,\n searchClient,\n suggestionsClient,\n topicsClient,\n hydrator,\n views,\n signingKey,\n idResolver,\n bsyncClient,\n stashClient,\n courierClient,\n rolodexClient,\n authVerifier,\n featureGatesClient,\n blobDispatcher,\n kwsClient,\n })\n\n const server = createServer([], {\n validateResponse: config.debugMode,\n payload: {\n jsonLimit: 100 * 1024, // 100kb\n textLimit: 100 * 1024, // 100kb\n blobLimit: 5 * 1024 * 1024, // 5mb\n },\n })\n\n API(server, ctx)\n\n app.use(health.createRouter(ctx))\n app.use(wellKnown.createRouter(ctx))\n app.use(blobResolver.createMiddleware(ctx))\n app.use(imageServer.createMiddleware(ctx, { prefix: '/img/' }))\n\n if (config.dataplaneUrls.length > 0 || config.dataplaneUrlsEtcdKeyPrefix) {\n app.use(sitemap.createRouter(ctx))\n }\n\n app.use(server.router)\n app.use(error.handler)\n app.use('/external', external.createRouter(ctx))\n\n return new BskyAppView({ ctx, app })\n }\n\n async start(): Promise<http.Server> {\n if (this.ctx.dataplaneHostList instanceof EtcdHostList) {\n await this.ctx.dataplaneHostList.connect()\n }\n this.ctx.featureGatesClient.start() // lazy, no await\n const server = this.app.listen(this.ctx.cfg.port)\n this.server = server\n server.keepAliveTimeout = 90000\n this.terminator = httpTerminator.createHttpTerminator({ server })\n await events.once(server, 'listening')\n const { port } = server.address() as AddressInfo\n this.ctx.cfg.assignPort(port)\n return server\n }\n\n async destroy(): Promise<void> {\n try {\n await this.ctx.featureGatesClient.destroy()\n } finally {\n try {\n await this.terminator?.terminate()\n } finally {\n await this.ctx.etcd?.close()\n }\n }\n }\n\n async [Symbol.asyncDispose]() {\n await this.destroy()\n }\n}\n\nexport default BskyAppView\n"]}
@@ -7,12 +7,14 @@ type RecordDeleted = {
7
7
  export type { RecordDeleted };
8
8
  declare const recordDeleted: l.TypedObjectSchema<"app.bsky.notification.defs#recordDeleted", l.Validator<RecordDeleted, RecordDeleted>>;
9
9
  export { recordDeleted };
10
+ /** @deprecated use chat.bsky.notification preferences instead. This will only return a default value. */
10
11
  type ChatPreference = {
11
12
  $type?: 'app.bsky.notification.defs#chatPreference';
12
13
  include: 'all' | 'accepted' | l.UnknownString;
13
14
  push: boolean;
14
15
  };
15
16
  export type { ChatPreference };
17
+ /** @deprecated use chat.bsky.notification preferences instead. This will only return a default value. */
16
18
  declare const chatPreference: l.TypedObjectSchema<"app.bsky.notification.defs#chatPreference", l.Validator<ChatPreference, ChatPreference>>;
17
19
  export { chatPreference };
18
20
  type FilterablePreference = {
@@ -34,6 +36,9 @@ declare const preference: l.TypedObjectSchema<"app.bsky.notification.defs#prefer
34
36
  export { preference };
35
37
  type Preferences = {
36
38
  $type?: 'app.bsky.notification.defs#preferences';
39
+ /**
40
+ * @deprecated use chat.bsky.notification preferences instead. This will only return a default value.
41
+ */
37
42
  chat: ChatPreference;
38
43
  follow: FilterablePreference;
39
44
  like: FilterablePreference;
@@ -1 +1 @@
1
- {"version":3,"file":"defs.defs.d.ts","sourceRoot":"","sources":["../../../../../src/lexicons/app/bsky/notification/defs.defs.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,cAAc,CAAA;AAEhC,QAAA,MAAM,KAAK,+BAA+B,CAAA;AAE1C,OAAO,EAAE,KAAK,EAAE,CAAA;AAEhB,KAAK,aAAa,GAAG;IAAE,KAAK,CAAC,EAAE,0CAA0C,CAAA;CAAE,CAAA;AAE3E,YAAY,EAAE,aAAa,EAAE,CAAA;AAE7B,QAAA,MAAM,aAAa,4GAIlB,CAAA;AAED,OAAO,EAAE,aAAa,EAAE,CAAA;AAExB,KAAK,cAAc,GAAG;IACpB,KAAK,CAAC,EAAE,2CAA2C,CAAA;IACnD,OAAO,EAAE,KAAK,GAAG,UAAU,GAAG,CAAC,CAAC,aAAa,CAAA;IAC7C,IAAI,EAAE,OAAO,CAAA;CACd,CAAA;AAED,YAAY,EAAE,cAAc,EAAE,CAAA;AAE9B,QAAA,MAAM,cAAc,+GAOnB,CAAA;AAED,OAAO,EAAE,cAAc,EAAE,CAAA;AAEzB,KAAK,oBAAoB,GAAG;IAC1B,KAAK,CAAC,EAAE,iDAAiD,CAAA;IACzD,OAAO,EAAE,KAAK,GAAG,SAAS,GAAG,CAAC,CAAC,aAAa,CAAA;IAC5C,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,OAAO,CAAA;CACd,CAAA;AAED,YAAY,EAAE,oBAAoB,EAAE,CAAA;AAEpC,QAAA,MAAM,oBAAoB,iIAQzB,CAAA;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAA;AAE/B,KAAK,UAAU,GAAG;IAChB,KAAK,CAAC,EAAE,uCAAuC,CAAA;IAC/C,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,OAAO,CAAA;CACd,CAAA;AAED,YAAY,EAAE,UAAU,EAAE,CAAA;AAE1B,QAAA,MAAM,UAAU,mGAOf,CAAA;AAED,OAAO,EAAE,UAAU,EAAE,CAAA;AAErB,KAAK,WAAW,GAAG;IACjB,KAAK,CAAC,EAAE,wCAAwC,CAAA;IAChD,IAAI,EAAE,cAAc,CAAA;IACpB,MAAM,EAAE,oBAAoB,CAAA;IAC5B,IAAI,EAAE,oBAAoB,CAAA;IAC1B,aAAa,EAAE,oBAAoB,CAAA;IACnC,OAAO,EAAE,oBAAoB,CAAA;IAC7B,KAAK,EAAE,oBAAoB,CAAA;IAC3B,KAAK,EAAE,oBAAoB,CAAA;IAC3B,MAAM,EAAE,oBAAoB,CAAA;IAC5B,eAAe,EAAE,oBAAoB,CAAA;IACrC,iBAAiB,EAAE,UAAU,CAAA;IAC7B,cAAc,EAAE,UAAU,CAAA;IAC1B,UAAU,EAAE,UAAU,CAAA;IACtB,QAAQ,EAAE,UAAU,CAAA;CACrB,CAAA;AAED,YAAY,EAAE,WAAW,EAAE,CAAA;AAE3B,QAAA,MAAM,WAAW,sGAoChB,CAAA;AAED,OAAO,EAAE,WAAW,EAAE,CAAA;AAEtB,KAAK,oBAAoB,GAAG;IAC1B,KAAK,CAAC,EAAE,iDAAiD,CAAA;IACzD,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAED,YAAY,EAAE,oBAAoB,EAAE,CAAA;AAEpC,QAAA,MAAM,oBAAoB,iIAOzB,CAAA;AAED,OAAO,EAAE,oBAAoB,EAAE,CAAA;AAE/B,gEAAgE;AAChE,KAAK,2BAA2B,GAAG;IACjC,KAAK,CAAC,EAAE,wDAAwD,CAAA;IAChE,OAAO,EAAE,CAAC,CAAC,SAAS,CAAA;IACpB,oBAAoB,EAAE,oBAAoB,CAAA;CAC3C,CAAA;AAED,YAAY,EAAE,2BAA2B,EAAE,CAAA;AAE3C,gEAAgE;AAChE,QAAA,MAAM,2BAA2B,sJAU9B,CAAA;AAEH,OAAO,EAAE,2BAA2B,EAAE,CAAA"}
1
+ {"version":3,"file":"defs.defs.d.ts","sourceRoot":"","sources":["../../../../../src/lexicons/app/bsky/notification/defs.defs.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ export { $nsid };
7
7
  const recordDeleted = /*#__PURE__*/ l.typedObject($nsid, 'recordDeleted',
8
8
  /*#__PURE__*/ l.object({}));
9
9
  export { recordDeleted };
10
+ /** @deprecated use chat.bsky.notification preferences instead. This will only return a default value. */
10
11
  const chatPreference = /*#__PURE__*/ l.typedObject($nsid, 'chatPreference',
11
12
  /*#__PURE__*/ l.object({
12
13
  include: /*#__PURE__*/ l.string(),
@@ -1 +1 @@
1
- {"version":3,"file":"defs.defs.js","sourceRoot":"","sources":["../../../../../src/lexicons/app/bsky/notification/defs.defs.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * THIS FILE WAS GENERATED BY \"@atproto/lex\". DO NOT EDIT.\n */\n\nimport { l } from '@atproto/lex'\n\nconst $nsid = 'app.bsky.notification.defs'\n\nexport { $nsid }\n\ntype RecordDeleted = { $type?: 'app.bsky.notification.defs#recordDeleted' }\n\nexport type { RecordDeleted }\n\nconst recordDeleted = /*#__PURE__*/ l.typedObject<RecordDeleted>(\n $nsid,\n 'recordDeleted',\n /*#__PURE__*/ l.object({}),\n)\n\nexport { recordDeleted }\n\ntype ChatPreference = {\n $type?: 'app.bsky.notification.defs#chatPreference'\n include: 'all' | 'accepted' | l.UnknownString\n push: boolean\n}\n\nexport type { ChatPreference }\n\nconst chatPreference = /*#__PURE__*/ l.typedObject<ChatPreference>(\n $nsid,\n 'chatPreference',\n /*#__PURE__*/ l.object({\n include: /*#__PURE__*/ l.string<{ knownValues: ['all', 'accepted'] }>(),\n push: /*#__PURE__*/ l.boolean(),\n }),\n)\n\nexport { chatPreference }\n\ntype FilterablePreference = {\n $type?: 'app.bsky.notification.defs#filterablePreference'\n include: 'all' | 'follows' | l.UnknownString\n list: boolean\n push: boolean\n}\n\nexport type { FilterablePreference }\n\nconst filterablePreference = /*#__PURE__*/ l.typedObject<FilterablePreference>(\n $nsid,\n 'filterablePreference',\n /*#__PURE__*/ l.object({\n include: /*#__PURE__*/ l.string<{ knownValues: ['all', 'follows'] }>(),\n list: /*#__PURE__*/ l.boolean(),\n push: /*#__PURE__*/ l.boolean(),\n }),\n)\n\nexport { filterablePreference }\n\ntype Preference = {\n $type?: 'app.bsky.notification.defs#preference'\n list: boolean\n push: boolean\n}\n\nexport type { Preference }\n\nconst preference = /*#__PURE__*/ l.typedObject<Preference>(\n $nsid,\n 'preference',\n /*#__PURE__*/ l.object({\n list: /*#__PURE__*/ l.boolean(),\n push: /*#__PURE__*/ l.boolean(),\n }),\n)\n\nexport { preference }\n\ntype Preferences = {\n $type?: 'app.bsky.notification.defs#preferences'\n chat: ChatPreference\n follow: FilterablePreference\n like: FilterablePreference\n likeViaRepost: FilterablePreference\n mention: FilterablePreference\n quote: FilterablePreference\n reply: FilterablePreference\n repost: FilterablePreference\n repostViaRepost: FilterablePreference\n starterpackJoined: Preference\n subscribedPost: Preference\n unverified: Preference\n verified: Preference\n}\n\nexport type { Preferences }\n\nconst preferences = /*#__PURE__*/ l.typedObject<Preferences>(\n $nsid,\n 'preferences',\n /*#__PURE__*/ l.object({\n chat: /*#__PURE__*/ l.ref<ChatPreference>((() => chatPreference) as any),\n follow: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n like: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n likeViaRepost: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n mention: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n quote: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n reply: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n repost: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n repostViaRepost: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n starterpackJoined: /*#__PURE__*/ l.ref<Preference>(\n (() => preference) as any,\n ),\n subscribedPost: /*#__PURE__*/ l.ref<Preference>((() => preference) as any),\n unverified: /*#__PURE__*/ l.ref<Preference>((() => preference) as any),\n verified: /*#__PURE__*/ l.ref<Preference>((() => preference) as any),\n }),\n)\n\nexport { preferences }\n\ntype ActivitySubscription = {\n $type?: 'app.bsky.notification.defs#activitySubscription'\n post: boolean\n reply: boolean\n}\n\nexport type { ActivitySubscription }\n\nconst activitySubscription = /*#__PURE__*/ l.typedObject<ActivitySubscription>(\n $nsid,\n 'activitySubscription',\n /*#__PURE__*/ l.object({\n post: /*#__PURE__*/ l.boolean(),\n reply: /*#__PURE__*/ l.boolean(),\n }),\n)\n\nexport { activitySubscription }\n\n/** Object used to store activity subscription data in stash. */\ntype SubjectActivitySubscription = {\n $type?: 'app.bsky.notification.defs#subjectActivitySubscription'\n subject: l.DidString\n activitySubscription: ActivitySubscription\n}\n\nexport type { SubjectActivitySubscription }\n\n/** Object used to store activity subscription data in stash. */\nconst subjectActivitySubscription =\n /*#__PURE__*/ l.typedObject<SubjectActivitySubscription>(\n $nsid,\n 'subjectActivitySubscription',\n /*#__PURE__*/ l.object({\n subject: /*#__PURE__*/ l.string({ format: 'did' }),\n activitySubscription: /*#__PURE__*/ l.ref<ActivitySubscription>(\n (() => activitySubscription) as any,\n ),\n }),\n )\n\nexport { subjectActivitySubscription }\n"]}
1
+ {"version":3,"file":"defs.defs.js","sourceRoot":"","sources":["../../../../../src/lexicons/app/bsky/notification/defs.defs.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * THIS FILE WAS GENERATED BY \"@atproto/lex\". DO NOT EDIT.\n */\n\nimport { l } from '@atproto/lex'\n\nconst $nsid = 'app.bsky.notification.defs'\n\nexport { $nsid }\n\ntype RecordDeleted = { $type?: 'app.bsky.notification.defs#recordDeleted' }\n\nexport type { RecordDeleted }\n\nconst recordDeleted = /*#__PURE__*/ l.typedObject<RecordDeleted>(\n $nsid,\n 'recordDeleted',\n /*#__PURE__*/ l.object({}),\n)\n\nexport { recordDeleted }\n\n/** @deprecated use chat.bsky.notification preferences instead. This will only return a default value. */\ntype ChatPreference = {\n $type?: 'app.bsky.notification.defs#chatPreference'\n include: 'all' | 'accepted' | l.UnknownString\n push: boolean\n}\n\nexport type { ChatPreference }\n\n/** @deprecated use chat.bsky.notification preferences instead. This will only return a default value. */\nconst chatPreference = /*#__PURE__*/ l.typedObject<ChatPreference>(\n $nsid,\n 'chatPreference',\n /*#__PURE__*/ l.object({\n include: /*#__PURE__*/ l.string<{ knownValues: ['all', 'accepted'] }>(),\n push: /*#__PURE__*/ l.boolean(),\n }),\n)\n\nexport { chatPreference }\n\ntype FilterablePreference = {\n $type?: 'app.bsky.notification.defs#filterablePreference'\n include: 'all' | 'follows' | l.UnknownString\n list: boolean\n push: boolean\n}\n\nexport type { FilterablePreference }\n\nconst filterablePreference = /*#__PURE__*/ l.typedObject<FilterablePreference>(\n $nsid,\n 'filterablePreference',\n /*#__PURE__*/ l.object({\n include: /*#__PURE__*/ l.string<{ knownValues: ['all', 'follows'] }>(),\n list: /*#__PURE__*/ l.boolean(),\n push: /*#__PURE__*/ l.boolean(),\n }),\n)\n\nexport { filterablePreference }\n\ntype Preference = {\n $type?: 'app.bsky.notification.defs#preference'\n list: boolean\n push: boolean\n}\n\nexport type { Preference }\n\nconst preference = /*#__PURE__*/ l.typedObject<Preference>(\n $nsid,\n 'preference',\n /*#__PURE__*/ l.object({\n list: /*#__PURE__*/ l.boolean(),\n push: /*#__PURE__*/ l.boolean(),\n }),\n)\n\nexport { preference }\n\ntype Preferences = {\n $type?: 'app.bsky.notification.defs#preferences'\n\n /**\n * @deprecated use chat.bsky.notification preferences instead. This will only return a default value.\n */\n chat: ChatPreference\n follow: FilterablePreference\n like: FilterablePreference\n likeViaRepost: FilterablePreference\n mention: FilterablePreference\n quote: FilterablePreference\n reply: FilterablePreference\n repost: FilterablePreference\n repostViaRepost: FilterablePreference\n starterpackJoined: Preference\n subscribedPost: Preference\n unverified: Preference\n verified: Preference\n}\n\nexport type { Preferences }\n\nconst preferences = /*#__PURE__*/ l.typedObject<Preferences>(\n $nsid,\n 'preferences',\n /*#__PURE__*/ l.object({\n chat: /*#__PURE__*/ l.ref<ChatPreference>((() => chatPreference) as any),\n follow: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n like: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n likeViaRepost: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n mention: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n quote: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n reply: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n repost: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n repostViaRepost: /*#__PURE__*/ l.ref<FilterablePreference>(\n (() => filterablePreference) as any,\n ),\n starterpackJoined: /*#__PURE__*/ l.ref<Preference>(\n (() => preference) as any,\n ),\n subscribedPost: /*#__PURE__*/ l.ref<Preference>((() => preference) as any),\n unverified: /*#__PURE__*/ l.ref<Preference>((() => preference) as any),\n verified: /*#__PURE__*/ l.ref<Preference>((() => preference) as any),\n }),\n)\n\nexport { preferences }\n\ntype ActivitySubscription = {\n $type?: 'app.bsky.notification.defs#activitySubscription'\n post: boolean\n reply: boolean\n}\n\nexport type { ActivitySubscription }\n\nconst activitySubscription = /*#__PURE__*/ l.typedObject<ActivitySubscription>(\n $nsid,\n 'activitySubscription',\n /*#__PURE__*/ l.object({\n post: /*#__PURE__*/ l.boolean(),\n reply: /*#__PURE__*/ l.boolean(),\n }),\n)\n\nexport { activitySubscription }\n\n/** Object used to store activity subscription data in stash. */\ntype SubjectActivitySubscription = {\n $type?: 'app.bsky.notification.defs#subjectActivitySubscription'\n subject: l.DidString\n activitySubscription: ActivitySubscription\n}\n\nexport type { SubjectActivitySubscription }\n\n/** Object used to store activity subscription data in stash. */\nconst subjectActivitySubscription =\n /*#__PURE__*/ l.typedObject<SubjectActivitySubscription>(\n $nsid,\n 'subjectActivitySubscription',\n /*#__PURE__*/ l.object({\n subject: /*#__PURE__*/ l.string({ format: 'did' }),\n activitySubscription: /*#__PURE__*/ l.ref<ActivitySubscription>(\n (() => activitySubscription) as any,\n ),\n }),\n )\n\nexport { subjectActivitySubscription }\n"]}