@atproto/bsky 0.0.37 → 0.0.39

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 (149) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/api/app/bsky/feed/getAuthorFeed.d.ts +2 -3
  3. package/dist/api/app/bsky/feed/getListFeed.d.ts +2 -2
  4. package/dist/api/app/bsky/feed/getTimeline.d.ts +4 -2
  5. package/dist/api/app/bsky/labeler/getServices.d.ts +3 -0
  6. package/dist/api/util.d.ts +9 -2
  7. package/dist/auth-verifier.d.ts +1 -1
  8. package/dist/context.d.ts +3 -0
  9. package/dist/data-plane/server/db/database-schema.d.ts +2 -2
  10. package/dist/data-plane/server/db/migrations/20240226T225725627Z-labelers.d.ts +3 -0
  11. package/dist/data-plane/server/db/migrations/index.d.ts +1 -0
  12. package/dist/data-plane/server/db/tables/labeler.d.ts +13 -0
  13. package/dist/data-plane/server/indexing/index.d.ts +2 -0
  14. package/dist/data-plane/server/indexing/plugins/labeler.d.ts +10 -0
  15. package/dist/data-plane/server/util.d.ts +6 -6
  16. package/dist/hydration/actor.d.ts +3 -0
  17. package/dist/hydration/hydrator.d.ts +27 -22
  18. package/dist/hydration/label.d.ts +23 -9
  19. package/dist/index.js +4100 -4645
  20. package/dist/index.js.map +3 -3
  21. package/dist/lexicon/index.d.ts +7 -27
  22. package/dist/lexicon/lexicons.d.ts +516 -1463
  23. package/dist/lexicon/types/app/bsky/actor/defs.d.ts +23 -1
  24. package/dist/lexicon/types/app/bsky/embed/record.d.ts +2 -1
  25. package/dist/lexicon/types/app/bsky/feed/defs.d.ts +1 -0
  26. package/dist/lexicon/types/app/bsky/graph/defs.d.ts +3 -0
  27. package/dist/lexicon/types/app/bsky/labeler/defs.d.ts +41 -0
  28. package/dist/lexicon/types/{com/atproto/admin/searchRepos.d.ts → app/bsky/labeler/getServices.d.ts} +7 -7
  29. package/dist/lexicon/types/app/bsky/labeler/service.d.ts +14 -0
  30. package/dist/lexicon/types/com/atproto/admin/defs.d.ts +0 -304
  31. package/dist/lexicon/types/com/atproto/label/defs.d.ts +23 -0
  32. package/dist/lexicon/types/com/atproto/server/describeServer.d.ts +7 -0
  33. package/dist/proto/bsky_connect.d.ts +7 -1
  34. package/dist/proto/bsky_pb.d.ts +25 -0
  35. package/dist/util.d.ts +7 -0
  36. package/dist/views/index.d.ts +3 -0
  37. package/dist/views/types.d.ts +2 -1
  38. package/package.json +14 -13
  39. package/proto/bsky.proto +12 -0
  40. package/src/api/app/bsky/actor/getProfile.ts +21 -17
  41. package/src/api/app/bsky/actor/getProfiles.ts +16 -7
  42. package/src/api/app/bsky/actor/getSuggestions.ts +18 -13
  43. package/src/api/app/bsky/actor/searchActors.ts +9 -5
  44. package/src/api/app/bsky/actor/searchActorsTypeahead.ts +12 -5
  45. package/src/api/app/bsky/feed/getActorFeeds.ts +16 -6
  46. package/src/api/app/bsky/feed/getActorLikes.ts +18 -8
  47. package/src/api/app/bsky/feed/getAuthorFeed.ts +18 -19
  48. package/src/api/app/bsky/feed/getFeed.ts +14 -7
  49. package/src/api/app/bsky/feed/getFeedGenerator.ts +8 -2
  50. package/src/api/app/bsky/feed/getFeedGenerators.ts +16 -5
  51. package/src/api/app/bsky/feed/getLikes.ts +13 -6
  52. package/src/api/app/bsky/feed/getListFeed.ts +13 -7
  53. package/src/api/app/bsky/feed/getPostThread.ts +15 -8
  54. package/src/api/app/bsky/feed/getPosts.ts +14 -5
  55. package/src/api/app/bsky/feed/getRepostedBy.ts +13 -6
  56. package/src/api/app/bsky/feed/getSuggestedFeeds.ts +8 -2
  57. package/src/api/app/bsky/feed/getTimeline.ts +14 -8
  58. package/src/api/app/bsky/feed/searchPosts.ts +9 -5
  59. package/src/api/app/bsky/graph/getBlocks.ts +10 -9
  60. package/src/api/app/bsky/graph/getFollowers.ts +23 -15
  61. package/src/api/app/bsky/graph/getFollows.ts +23 -15
  62. package/src/api/app/bsky/graph/getList.ts +14 -8
  63. package/src/api/app/bsky/graph/getListBlocks.ts +10 -7
  64. package/src/api/app/bsky/graph/getListMutes.ts +10 -7
  65. package/src/api/app/bsky/graph/getLists.ts +9 -7
  66. package/src/api/app/bsky/graph/getMutes.ts +10 -8
  67. package/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts +10 -7
  68. package/src/api/app/bsky/graph/muteActor.ts +1 -1
  69. package/src/api/app/bsky/labeler/getServices.ts +46 -0
  70. package/src/api/app/bsky/notification/listNotifications.ts +12 -8
  71. package/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +6 -3
  72. package/src/api/com/atproto/admin/getAccountInfos.ts +10 -3
  73. package/src/api/index.ts +2 -0
  74. package/src/api/util.ts +19 -4
  75. package/src/auth-verifier.ts +2 -2
  76. package/src/context.ts +20 -0
  77. package/src/data-plane/server/db/database-schema.ts +4 -4
  78. package/src/data-plane/server/db/migrations/20240226T225725627Z-labelers.ts +27 -0
  79. package/src/data-plane/server/db/migrations/index.ts +1 -0
  80. package/src/data-plane/server/db/tables/labeler.ts +16 -0
  81. package/src/data-plane/server/indexing/index.ts +4 -0
  82. package/src/data-plane/server/indexing/plugins/labeler.ts +77 -0
  83. package/src/data-plane/server/routes/interactions.ts +17 -1
  84. package/src/data-plane/server/routes/labels.ts +4 -2
  85. package/src/data-plane/server/routes/profile.ts +15 -1
  86. package/src/data-plane/server/routes/records.ts +1 -0
  87. package/src/hydration/actor.ts +6 -0
  88. package/src/hydration/hydrator.ts +171 -97
  89. package/src/hydration/label.ts +106 -20
  90. package/src/index.ts +1 -3
  91. package/src/lexicon/index.ts +22 -137
  92. package/src/lexicon/lexicons.ts +552 -1635
  93. package/src/lexicon/types/app/bsky/actor/defs.ts +57 -1
  94. package/src/lexicon/types/app/bsky/embed/record.ts +2 -0
  95. package/src/lexicon/types/app/bsky/feed/defs.ts +1 -0
  96. package/src/lexicon/types/app/bsky/graph/defs.ts +3 -0
  97. package/src/lexicon/types/app/bsky/labeler/defs.ts +93 -0
  98. package/src/lexicon/types/{com/atproto/admin/searchRepos.ts → app/bsky/labeler/getServices.ts} +8 -8
  99. package/src/lexicon/types/app/bsky/labeler/service.ts +31 -0
  100. package/src/lexicon/types/com/atproto/admin/defs.ts +0 -694
  101. package/src/lexicon/types/com/atproto/label/defs.ts +78 -0
  102. package/src/lexicon/types/com/atproto/server/describeServer.ts +18 -0
  103. package/src/proto/bsky_connect.ts +11 -0
  104. package/src/proto/bsky_pb.ts +146 -0
  105. package/src/util.ts +44 -0
  106. package/src/views/index.ts +77 -8
  107. package/src/views/types.ts +6 -3
  108. package/tests/__snapshots__/feed-generation.test.ts.snap +12 -45
  109. package/tests/_util.ts +21 -0
  110. package/tests/data-plane/__snapshots__/indexing.test.ts.snap +20 -8
  111. package/tests/label-hydration.test.ts +162 -0
  112. package/tests/views/__snapshots__/author-feed.test.ts.snap +0 -46
  113. package/tests/views/__snapshots__/block-lists.test.ts.snap +7 -17
  114. package/tests/views/__snapshots__/blocks.test.ts.snap +0 -9
  115. package/tests/views/__snapshots__/labeler-service.test.ts.snap +156 -0
  116. package/tests/views/__snapshots__/list-feed.test.ts.snap +0 -20
  117. package/tests/views/__snapshots__/mute-lists.test.ts.snap +10 -18
  118. package/tests/views/__snapshots__/mutes.test.ts.snap +0 -4
  119. package/tests/views/__snapshots__/notifications.test.ts.snap +0 -9
  120. package/tests/views/__snapshots__/posts.test.ts.snap +0 -7
  121. package/tests/views/__snapshots__/profile.test.ts.snap +40 -6
  122. package/tests/views/__snapshots__/thread.test.ts.snap +0 -38
  123. package/tests/views/__snapshots__/threadgating.test.ts.snap +2 -0
  124. package/tests/views/__snapshots__/timeline.test.ts.snap +0 -145
  125. package/tests/views/labeler-service.test.ts +156 -0
  126. package/tests/views/takedown-labels.test.ts +133 -0
  127. package/tests/views/timeline.test.ts +7 -2
  128. package/dist/data-plane/server/db/tables/moderation.d.ts +0 -42
  129. package/dist/lexicon/types/com/atproto/admin/createCommunicationTemplate.d.ts +0 -37
  130. package/dist/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.d.ts +0 -25
  131. package/dist/lexicon/types/com/atproto/admin/emitModerationEvent.d.ts +0 -45
  132. package/dist/lexicon/types/com/atproto/admin/getModerationEvent.d.ts +0 -29
  133. package/dist/lexicon/types/com/atproto/admin/getRecord.d.ts +0 -31
  134. package/dist/lexicon/types/com/atproto/admin/getRepo.d.ts +0 -30
  135. package/dist/lexicon/types/com/atproto/admin/listCommunicationTemplates.d.ts +0 -31
  136. package/dist/lexicon/types/com/atproto/admin/queryModerationEvents.d.ts +0 -48
  137. package/dist/lexicon/types/com/atproto/admin/queryModerationStatuses.d.ts +0 -50
  138. package/dist/lexicon/types/com/atproto/admin/updateCommunicationTemplate.d.ts +0 -39
  139. package/src/data-plane/server/db/tables/moderation.ts +0 -59
  140. package/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts +0 -54
  141. package/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts +0 -38
  142. package/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts +0 -67
  143. package/src/lexicon/types/com/atproto/admin/getModerationEvent.ts +0 -41
  144. package/src/lexicon/types/com/atproto/admin/getRecord.ts +0 -43
  145. package/src/lexicon/types/com/atproto/admin/getRepo.ts +0 -42
  146. package/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts +0 -44
  147. package/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts +0 -73
  148. package/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts +0 -74
  149. package/src/lexicon/types/com/atproto/admin/updateCommunicationTemplate.ts +0 -57
@@ -19,6 +19,7 @@ import {
19
19
  SkeletonFnInput,
20
20
  createPipeline,
21
21
  } from '../../../../pipeline'
22
+ import { HydrateCtx } from '../../../../hydration/hydrator'
22
23
  import { FeedItem } from '../../../../hydration/feed'
23
24
  import { GetIdentityByDidResponse } from '../../../../proto/bsky_pb'
24
25
  import {
@@ -27,6 +28,7 @@ import {
27
28
  isDataplaneError,
28
29
  unpackIdentityServices,
29
30
  } from '../../../../data-plane'
31
+ import { resHeaders } from '../../../util'
30
32
 
31
33
  export default function (server: Server, ctx: AppContext) {
32
34
  const getFeed = createPipeline(
@@ -39,21 +41,26 @@ export default function (server: Server, ctx: AppContext) {
39
41
  auth: ctx.authVerifier.standardOptionalAnyAud,
40
42
  handler: async ({ params, auth, req }) => {
41
43
  const viewer = auth.credentials.iss
44
+ const labelers = ctx.reqLabelers(req)
45
+ const hydrateCtx = { labelers, viewer }
42
46
  const headers = noUndefinedVals({
43
47
  authorization: req.headers['authorization'],
44
48
  'accept-language': req.headers['accept-language'],
45
49
  })
46
50
  // @NOTE feed cursors should not be affected by appview swap
47
- const { timerSkele, timerHydr, resHeaders, ...result } = await getFeed(
48
- { ...params, viewer, headers },
49
- ctx,
50
- )
51
+ const {
52
+ timerSkele,
53
+ timerHydr,
54
+ resHeaders: feedResHeaders,
55
+ ...result
56
+ } = await getFeed({ ...params, hydrateCtx, headers }, ctx)
51
57
 
52
58
  return {
53
59
  encoding: 'application/json',
54
60
  body: result,
55
61
  headers: {
56
- ...(resHeaders ?? {}),
62
+ ...(feedResHeaders ?? {}),
63
+ ...resHeaders({ labelers }),
57
64
  'server-timing': serverTimingHeader([timerSkele, timerHydr]),
58
65
  },
59
66
  }
@@ -90,7 +97,7 @@ const hydration = async (
90
97
  const timerHydr = new ServerTimer('hydr').start()
91
98
  const hydration = await ctx.hydrator.hydrateFeedItems(
92
99
  skeleton.items,
93
- params.viewer,
100
+ params.hydrateCtx,
94
101
  )
95
102
  skeleton.timerHydr = timerHydr.stop()
96
103
  return hydration
@@ -130,7 +137,7 @@ const presentation = (
130
137
  type Context = AppContext
131
138
 
132
139
  type Params = GetFeedParams & {
133
- viewer: string | null
140
+ hydrateCtx: HydrateCtx
134
141
  headers: Record<string, string>
135
142
  }
136
143
 
@@ -8,15 +8,20 @@ import {
8
8
  isDataplaneError,
9
9
  unpackIdentityServices,
10
10
  } from '../../../../data-plane'
11
+ import { resHeaders } from '../../../util'
11
12
 
12
13
  export default function (server: Server, ctx: AppContext) {
13
14
  server.app.bsky.feed.getFeedGenerator({
14
15
  auth: ctx.authVerifier.standardOptional,
15
- handler: async ({ params, auth }) => {
16
+ handler: async ({ params, auth, req }) => {
16
17
  const { feed } = params
17
18
  const viewer = auth.credentials.iss
19
+ const labelers = ctx.reqLabelers(req)
18
20
 
19
- const hydration = await ctx.hydrator.hydrateFeedGens([feed], viewer)
21
+ const hydration = await ctx.hydrator.hydrateFeedGens([feed], {
22
+ viewer,
23
+ labelers,
24
+ })
20
25
  const feedInfo = hydration.feedgens?.get(feed)
21
26
  if (!feedInfo) {
22
27
  throw new InvalidRequestError('could not find feed')
@@ -59,6 +64,7 @@ export default function (server: Server, ctx: AppContext) {
59
64
  isOnline: true,
60
65
  isValid: true,
61
66
  },
67
+ headers: resHeaders({ labelers }),
62
68
  }
63
69
  },
64
70
  })
@@ -3,8 +3,13 @@ import { Server } from '../../../../lexicon'
3
3
  import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getFeedGenerators'
4
4
  import AppContext from '../../../../context'
5
5
  import { createPipeline, noRules } from '../../../../pipeline'
6
- import { HydrationState, Hydrator } from '../../../../hydration/hydrator'
6
+ import {
7
+ HydrateCtx,
8
+ HydrationState,
9
+ Hydrator,
10
+ } from '../../../../hydration/hydrator'
7
11
  import { Views } from '../../../../views'
12
+ import { resHeaders } from '../../../util'
8
13
 
9
14
  export default function (server: Server, ctx: AppContext) {
10
15
  const getFeedGenerators = createPipeline(
@@ -15,12 +20,15 @@ export default function (server: Server, ctx: AppContext) {
15
20
  )
16
21
  server.app.bsky.feed.getFeedGenerators({
17
22
  auth: ctx.authVerifier.standardOptional,
18
- handler: async ({ params, auth }) => {
23
+ handler: async ({ params, auth, req }) => {
19
24
  const viewer = auth.credentials.iss
20
- const view = await getFeedGenerators({ ...params, viewer }, ctx)
25
+ const labelers = ctx.reqLabelers(req)
26
+ const hydrateCtx = { labelers, viewer }
27
+ const view = await getFeedGenerators({ ...params, hydrateCtx }, ctx)
21
28
  return {
22
29
  encoding: 'application/json',
23
30
  body: view,
31
+ headers: resHeaders({ labelers }),
24
32
  }
25
33
  },
26
34
  })
@@ -38,7 +46,10 @@ const hydration = async (inputs: {
38
46
  skeleton: Skeleton
39
47
  }) => {
40
48
  const { ctx, params, skeleton } = inputs
41
- return await ctx.hydrator.hydrateFeedGens(skeleton.feedUris, params.viewer)
49
+ return await ctx.hydrator.hydrateFeedGens(
50
+ skeleton.feedUris,
51
+ params.hydrateCtx,
52
+ )
42
53
  }
43
54
 
44
55
  const presentation = (inputs: {
@@ -60,7 +71,7 @@ type Context = {
60
71
  views: Views
61
72
  }
62
73
 
63
- type Params = QueryParams & { viewer: string | null }
74
+ type Params = QueryParams & { hydrateCtx: HydrateCtx }
64
75
 
65
76
  type Skeleton = {
66
77
  feedUris: string[]
@@ -4,23 +4,30 @@ import { Server } from '../../../../lexicon'
4
4
  import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getLikes'
5
5
  import AppContext from '../../../../context'
6
6
  import { createPipeline } from '../../../../pipeline'
7
- import { HydrationState, Hydrator } from '../../../../hydration/hydrator'
7
+ import {
8
+ HydrateCtx,
9
+ HydrationState,
10
+ Hydrator,
11
+ } from '../../../../hydration/hydrator'
8
12
  import { Views } from '../../../../views'
9
13
  import { parseString } from '../../../../hydration/util'
10
14
  import { creatorFromUri } from '../../../../views/util'
11
- import { clearlyBadCursor } from '../../../util'
15
+ import { clearlyBadCursor, resHeaders } from '../../../util'
12
16
 
13
17
  export default function (server: Server, ctx: AppContext) {
14
18
  const getLikes = createPipeline(skeleton, hydration, noBlocks, presentation)
15
19
  server.app.bsky.feed.getLikes({
16
20
  auth: ctx.authVerifier.standardOptional,
17
- handler: async ({ params, auth }) => {
21
+ handler: async ({ params, auth, req }) => {
18
22
  const viewer = auth.credentials.iss
19
- const result = await getLikes({ ...params, viewer }, ctx)
23
+ const labelers = ctx.reqLabelers(req)
24
+ const hydrateCtx = { labelers, viewer }
25
+ const result = await getLikes({ ...params, hydrateCtx }, ctx)
20
26
 
21
27
  return {
22
28
  encoding: 'application/json',
23
29
  body: result,
30
+ headers: resHeaders({ labelers }),
24
31
  }
25
32
  },
26
33
  })
@@ -51,7 +58,7 @@ const hydration = async (inputs: {
51
58
  skeleton: Skeleton
52
59
  }) => {
53
60
  const { ctx, params, skeleton } = inputs
54
- return await ctx.hydrator.hydrateLikes(skeleton.likes, params.viewer)
61
+ return await ctx.hydrator.hydrateLikes(skeleton.likes, params.hydrateCtx)
55
62
  }
56
63
 
57
64
  const noBlocks = (inputs: {
@@ -103,7 +110,7 @@ type Context = {
103
110
  views: Views
104
111
  }
105
112
 
106
- type Params = QueryParams & { viewer: string | null }
113
+ type Params = QueryParams & { hydrateCtx: HydrateCtx }
107
114
 
108
115
  type Skeleton = {
109
116
  likes: string[]
@@ -1,9 +1,13 @@
1
1
  import { Server } from '../../../../lexicon'
2
2
  import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getListFeed'
3
3
  import AppContext from '../../../../context'
4
- import { clearlyBadCursor, setRepoRev } from '../../../util'
4
+ import { clearlyBadCursor, resHeaders } from '../../../util'
5
5
  import { createPipeline } from '../../../../pipeline'
6
- import { HydrationState, Hydrator } from '../../../../hydration/hydrator'
6
+ import {
7
+ HydrateCtx,
8
+ HydrationState,
9
+ Hydrator,
10
+ } from '../../../../hydration/hydrator'
7
11
  import { Views } from '../../../../views'
8
12
  import { DataPlaneClient } from '../../../../data-plane'
9
13
  import { mapDefined } from '@atproto/common'
@@ -19,17 +23,19 @@ export default function (server: Server, ctx: AppContext) {
19
23
  )
20
24
  server.app.bsky.feed.getListFeed({
21
25
  auth: ctx.authVerifier.standardOptional,
22
- handler: async ({ params, auth, res }) => {
26
+ handler: async ({ params, auth, req }) => {
23
27
  const viewer = auth.credentials.iss
28
+ const labelers = ctx.reqLabelers(req)
29
+ const hydrateCtx = { labelers, viewer }
24
30
 
25
- const result = await getListFeed({ ...params, viewer }, ctx)
31
+ const result = await getListFeed({ ...params, hydrateCtx }, ctx)
26
32
 
27
33
  const repoRev = await ctx.hydrator.actor.getRepoRevSafe(viewer)
28
- setRepoRev(res, repoRev)
29
34
 
30
35
  return {
31
36
  encoding: 'application/json',
32
37
  body: result,
38
+ headers: resHeaders({ labelers, repoRev }),
33
39
  }
34
40
  },
35
41
  })
@@ -65,7 +71,7 @@ const hydration = async (inputs: {
65
71
  skeleton: Skeleton
66
72
  }): Promise<HydrationState> => {
67
73
  const { ctx, params, skeleton } = inputs
68
- return ctx.hydrator.hydrateFeedItems(skeleton.items, params.viewer)
74
+ return ctx.hydrator.hydrateFeedItems(skeleton.items, params.hydrateCtx)
69
75
  }
70
76
 
71
77
  const noBlocksOrMutes = (inputs: {
@@ -104,7 +110,7 @@ type Context = {
104
110
  dataplane: DataPlaneClient
105
111
  }
106
112
 
107
- type Params = QueryParams & { viewer: string | null }
113
+ type Params = QueryParams & { hydrateCtx: HydrateCtx }
108
114
 
109
115
  type Skeleton = {
110
116
  items: FeedItem[]
@@ -6,7 +6,7 @@ import {
6
6
  OutputSchema,
7
7
  } from '../../../../lexicon/types/app/bsky/feed/getPostThread'
8
8
  import AppContext from '../../../../context'
9
- import { setRepoRev } from '../../../util'
9
+ import { ATPROTO_REPO_REV, resHeaders } from '../../../util'
10
10
  import {
11
11
  HydrationFnInput,
12
12
  PresentationFnInput,
@@ -14,7 +14,7 @@ import {
14
14
  createPipeline,
15
15
  noRules,
16
16
  } from '../../../../pipeline'
17
- import { Hydrator } from '../../../../hydration/hydrator'
17
+ import { HydrateCtx, Hydrator } from '../../../../hydration/hydrator'
18
18
  import { Views } from '../../../../views'
19
19
  import { DataPlaneClient, isDataplaneError, Code } from '../../../../data-plane'
20
20
 
@@ -27,24 +27,31 @@ export default function (server: Server, ctx: AppContext) {
27
27
  )
28
28
  server.app.bsky.feed.getPostThread({
29
29
  auth: ctx.authVerifier.optionalStandardOrRole,
30
- handler: async ({ params, auth, res }) => {
30
+ handler: async ({ params, auth, req, res }) => {
31
31
  const { viewer } = ctx.authVerifier.parseCreds(auth)
32
+ const labelers = ctx.reqLabelers(req)
33
+ const hydrateCtx = { labelers, viewer }
32
34
 
33
35
  let result: OutputSchema
34
36
  try {
35
- result = await getPostThread({ ...params, viewer }, ctx)
37
+ result = await getPostThread({ ...params, hydrateCtx }, ctx)
36
38
  } catch (err) {
37
39
  const repoRev = await ctx.hydrator.actor.getRepoRevSafe(viewer)
38
- setRepoRev(res, repoRev)
40
+ if (repoRev) {
41
+ res.setHeader(ATPROTO_REPO_REV, repoRev)
42
+ }
39
43
  throw err
40
44
  }
41
45
 
42
46
  const repoRev = await ctx.hydrator.actor.getRepoRevSafe(viewer)
43
- setRepoRev(res, repoRev)
44
47
 
45
48
  return {
46
49
  encoding: 'application/json',
47
50
  body: result,
51
+ headers: resHeaders({
52
+ repoRev,
53
+ labelers,
54
+ }),
48
55
  }
49
56
  },
50
57
  })
@@ -80,7 +87,7 @@ const hydration = async (
80
87
  const { ctx, params, skeleton } = inputs
81
88
  return ctx.hydrator.hydrateThreadPosts(
82
89
  skeleton.uris.map((uri) => ({ uri })),
83
- params.viewer,
90
+ params.hydrateCtx,
84
91
  )
85
92
  }
86
93
 
@@ -105,7 +112,7 @@ type Context = {
105
112
  views: Views
106
113
  }
107
114
 
108
- type Params = QueryParams & { viewer: string | null }
115
+ type Params = QueryParams & { hydrateCtx: HydrateCtx }
109
116
 
110
117
  type Skeleton = {
111
118
  anchor: string
@@ -3,21 +3,30 @@ import { Server } from '../../../../lexicon'
3
3
  import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getPosts'
4
4
  import AppContext from '../../../../context'
5
5
  import { createPipeline } from '../../../../pipeline'
6
- import { HydrationState, Hydrator } from '../../../../hydration/hydrator'
6
+ import {
7
+ HydrateCtx,
8
+ HydrationState,
9
+ Hydrator,
10
+ } from '../../../../hydration/hydrator'
7
11
  import { Views } from '../../../../views'
8
12
  import { creatorFromUri } from '../../../../views/util'
13
+ import { resHeaders } from '../../../util'
9
14
 
10
15
  export default function (server: Server, ctx: AppContext) {
11
16
  const getPosts = createPipeline(skeleton, hydration, noBlocks, presentation)
12
17
  server.app.bsky.feed.getPosts({
13
18
  auth: ctx.authVerifier.standardOptional,
14
- handler: async ({ params, auth }) => {
19
+ handler: async ({ params, auth, req }) => {
15
20
  const viewer = auth.credentials.iss
16
- const results = await getPosts({ ...params, viewer }, ctx)
21
+ const labelers = ctx.reqLabelers(req)
22
+ const hydrateCtx = { labelers, viewer }
23
+
24
+ const results = await getPosts({ ...params, hydrateCtx }, ctx)
17
25
 
18
26
  return {
19
27
  encoding: 'application/json',
20
28
  body: results,
29
+ headers: resHeaders({ labelers }),
21
30
  }
22
31
  },
23
32
  })
@@ -35,7 +44,7 @@ const hydration = async (inputs: {
35
44
  const { ctx, params, skeleton } = inputs
36
45
  return ctx.hydrator.hydratePosts(
37
46
  skeleton.posts.map((uri) => ({ uri })),
38
- params.viewer,
47
+ params.hydrateCtx,
39
48
  )
40
49
  }
41
50
 
@@ -70,7 +79,7 @@ type Context = {
70
79
  views: Views
71
80
  }
72
81
 
73
- type Params = QueryParams & { viewer: string | null }
82
+ type Params = QueryParams & { hydrateCtx: HydrateCtx }
74
83
 
75
84
  type Skeleton = {
76
85
  posts: string[]
@@ -3,11 +3,15 @@ import { Server } from '../../../../lexicon'
3
3
  import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getRepostedBy'
4
4
  import AppContext from '../../../../context'
5
5
  import { createPipeline } from '../../../../pipeline'
6
- import { HydrationState, Hydrator } from '../../../../hydration/hydrator'
6
+ import {
7
+ HydrateCtx,
8
+ HydrationState,
9
+ Hydrator,
10
+ } from '../../../../hydration/hydrator'
7
11
  import { Views } from '../../../../views'
8
12
  import { parseString } from '../../../../hydration/util'
9
13
  import { creatorFromUri } from '../../../../views/util'
10
- import { clearlyBadCursor } from '../../../util'
14
+ import { clearlyBadCursor, resHeaders } from '../../../util'
11
15
 
12
16
  export default function (server: Server, ctx: AppContext) {
13
17
  const getRepostedBy = createPipeline(
@@ -18,13 +22,16 @@ export default function (server: Server, ctx: AppContext) {
18
22
  )
19
23
  server.app.bsky.feed.getRepostedBy({
20
24
  auth: ctx.authVerifier.standardOptional,
21
- handler: async ({ params, auth }) => {
25
+ handler: async ({ params, auth, req }) => {
22
26
  const viewer = auth.credentials.iss
23
- const result = await getRepostedBy({ ...params, viewer }, ctx)
27
+ const labelers = ctx.reqLabelers(req)
28
+ const hydrateCtx = { labelers, viewer }
29
+ const result = await getRepostedBy({ ...params, hydrateCtx }, ctx)
24
30
 
25
31
  return {
26
32
  encoding: 'application/json',
27
33
  body: result,
34
+ headers: resHeaders({ labelers }),
28
35
  }
29
36
  },
30
37
  })
@@ -55,7 +62,7 @@ const hydration = async (inputs: {
55
62
  skeleton: Skeleton
56
63
  }) => {
57
64
  const { ctx, params, skeleton } = inputs
58
- return await ctx.hydrator.hydrateReposts(skeleton.reposts, params.viewer)
65
+ return await ctx.hydrator.hydrateReposts(skeleton.reposts, params.hydrateCtx)
59
66
  }
60
67
 
61
68
  const noBlocks = (inputs: {
@@ -99,7 +106,7 @@ type Context = {
99
106
  views: Views
100
107
  }
101
108
 
102
- type Params = QueryParams & { viewer: string | null }
109
+ type Params = QueryParams & { hydrateCtx: HydrateCtx }
103
110
 
104
111
  type Skeleton = {
105
112
  reposts: string[]
@@ -2,12 +2,14 @@ import { mapDefined } from '@atproto/common'
2
2
  import { Server } from '../../../../lexicon'
3
3
  import AppContext from '../../../../context'
4
4
  import { parseString } from '../../../../hydration/util'
5
+ import { resHeaders } from '../../../util'
5
6
 
6
7
  export default function (server: Server, ctx: AppContext) {
7
8
  server.app.bsky.feed.getSuggestedFeeds({
8
9
  auth: ctx.authVerifier.standardOptional,
9
- handler: async ({ auth, params }) => {
10
+ handler: async ({ auth, params, req }) => {
10
11
  const viewer = auth.credentials.iss
12
+ const labelers = ctx.reqLabelers(req)
11
13
 
12
14
  // @NOTE no need to coordinate the cursor for appview swap, as v1 doesn't use the cursor
13
15
  const suggestedRes = await ctx.dataplane.getSuggestedFeeds({
@@ -16,7 +18,10 @@ export default function (server: Server, ctx: AppContext) {
16
18
  cursor: params.cursor,
17
19
  })
18
20
  const uris = suggestedRes.uris
19
- const hydration = await ctx.hydrator.hydrateFeedGens(uris, viewer)
21
+ const hydration = await ctx.hydrator.hydrateFeedGens(uris, {
22
+ labelers,
23
+ viewer,
24
+ })
20
25
  const feedViews = mapDefined(uris, (uri) =>
21
26
  ctx.views.feedGenerator(uri, hydration),
22
27
  )
@@ -27,6 +32,7 @@ export default function (server: Server, ctx: AppContext) {
27
32
  feeds: feedViews,
28
33
  cursor: parseString(suggestedRes.cursor),
29
34
  },
35
+ headers: resHeaders({ labelers }),
30
36
  }
31
37
  },
32
38
  })
@@ -1,9 +1,13 @@
1
1
  import { Server } from '../../../../lexicon'
2
2
  import AppContext from '../../../../context'
3
3
  import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getTimeline'
4
- import { clearlyBadCursor, setRepoRev } from '../../../util'
4
+ import { clearlyBadCursor, resHeaders } from '../../../util'
5
5
  import { createPipeline } from '../../../../pipeline'
6
- import { HydrationState, Hydrator } from '../../../../hydration/hydrator'
6
+ import {
7
+ HydrateCtx,
8
+ HydrationState,
9
+ Hydrator,
10
+ } from '../../../../hydration/hydrator'
7
11
  import { Views } from '../../../../views'
8
12
  import { DataPlaneClient } from '../../../../data-plane'
9
13
  import { parseString } from '../../../../hydration/util'
@@ -19,17 +23,19 @@ export default function (server: Server, ctx: AppContext) {
19
23
  )
20
24
  server.app.bsky.feed.getTimeline({
21
25
  auth: ctx.authVerifier.standard,
22
- handler: async ({ params, auth, res }) => {
26
+ handler: async ({ params, auth, req }) => {
23
27
  const viewer = auth.credentials.iss
28
+ const labelers = ctx.reqLabelers(req)
29
+ const hydrateCtx = { labelers, viewer }
24
30
 
25
- const result = await getTimeline({ ...params, viewer }, ctx)
31
+ const result = await getTimeline({ ...params, hydrateCtx }, ctx)
26
32
 
27
33
  const repoRev = await ctx.hydrator.actor.getRepoRevSafe(viewer)
28
- setRepoRev(res, repoRev)
29
34
 
30
35
  return {
31
36
  encoding: 'application/json',
32
37
  body: result,
38
+ headers: resHeaders({ labelers, repoRev }),
33
39
  }
34
40
  },
35
41
  })
@@ -44,7 +50,7 @@ export const skeleton = async (inputs: {
44
50
  return { items: [] }
45
51
  }
46
52
  const res = await ctx.dataplane.getTimeline({
47
- actorDid: params.viewer,
53
+ actorDid: params.hydrateCtx.viewer,
48
54
  limit: params.limit,
49
55
  cursor: params.cursor,
50
56
  })
@@ -65,7 +71,7 @@ const hydration = async (inputs: {
65
71
  skeleton: Skeleton
66
72
  }): Promise<HydrationState> => {
67
73
  const { ctx, params, skeleton } = inputs
68
- return ctx.hydrator.hydrateFeedItems(skeleton.items, params.viewer)
74
+ return ctx.hydrator.hydrateFeedItems(skeleton.items, params.hydrateCtx)
69
75
  }
70
76
 
71
77
  const noBlocksOrMutes = (inputs: {
@@ -104,7 +110,7 @@ type Context = {
104
110
  dataplane: DataPlaneClient
105
111
  }
106
112
 
107
- type Params = QueryParams & { viewer: string }
113
+ type Params = QueryParams & { hydrateCtx: HydrateCtx & { viewer: string } }
108
114
 
109
115
  type Skeleton = {
110
116
  items: FeedItem[]
@@ -10,11 +10,12 @@ import {
10
10
  SkeletonFnInput,
11
11
  createPipeline,
12
12
  } from '../../../../pipeline'
13
- import { Hydrator } from '../../../../hydration/hydrator'
13
+ import { HydrateCtx, Hydrator } from '../../../../hydration/hydrator'
14
14
  import { Views } from '../../../../views'
15
15
  import { DataPlaneClient } from '../../../../data-plane'
16
16
  import { parseString } from '../../../../hydration/util'
17
17
  import { creatorFromUri } from '../../../../views/util'
18
+ import { resHeaders } from '../../../util'
18
19
 
19
20
  export default function (server: Server, ctx: AppContext) {
20
21
  const searchPosts = createPipeline(
@@ -25,12 +26,15 @@ export default function (server: Server, ctx: AppContext) {
25
26
  )
26
27
  server.app.bsky.feed.searchPosts({
27
28
  auth: ctx.authVerifier.standardOptional,
28
- handler: async ({ auth, params }) => {
29
+ handler: async ({ auth, params, req }) => {
29
30
  const viewer = auth.credentials.iss
30
- const results = await searchPosts({ ...params, viewer }, ctx)
31
+ const labelers = ctx.reqLabelers(req)
32
+ const hydrateCtx = { labelers, viewer }
33
+ const results = await searchPosts({ ...params, hydrateCtx }, ctx)
31
34
  return {
32
35
  encoding: 'application/json',
33
36
  body: results,
37
+ headers: resHeaders({ labelers }),
34
38
  }
35
39
  },
36
40
  })
@@ -70,7 +74,7 @@ const hydration = async (
70
74
  const { ctx, params, skeleton } = inputs
71
75
  return ctx.hydrator.hydratePosts(
72
76
  skeleton.posts.map((uri) => ({ uri })),
73
- params.viewer,
77
+ params.hydrateCtx,
74
78
  )
75
79
  }
76
80
 
@@ -104,7 +108,7 @@ type Context = {
104
108
  searchAgent?: AtpAgent
105
109
  }
106
110
 
107
- type Params = QueryParams & { viewer: string | null }
111
+ type Params = QueryParams & { hydrateCtx: HydrateCtx }
108
112
 
109
113
  type Skeleton = {
110
114
  posts: string[]
@@ -9,20 +9,23 @@ import {
9
9
  PresentationFnInput,
10
10
  SkeletonFnInput,
11
11
  } from '../../../../pipeline'
12
- import { Hydrator } from '../../../../hydration/hydrator'
12
+ import { HydrateCtx, Hydrator } from '../../../../hydration/hydrator'
13
13
  import { Views } from '../../../../views'
14
- import { clearlyBadCursor } from '../../../util'
14
+ import { clearlyBadCursor, resHeaders } from '../../../util'
15
15
 
16
16
  export default function (server: Server, ctx: AppContext) {
17
17
  const getBlocks = createPipeline(skeleton, hydration, noRules, presentation)
18
18
  server.app.bsky.graph.getBlocks({
19
19
  auth: ctx.authVerifier.standard,
20
- handler: async ({ params, auth }) => {
20
+ handler: async ({ params, auth, req }) => {
21
21
  const viewer = auth.credentials.iss
22
- const result = await getBlocks({ ...params, viewer }, ctx)
22
+ const labelers = ctx.reqLabelers(req)
23
+ const hydrateCtx = { labelers, viewer }
24
+ const result = await getBlocks({ ...params, hydrateCtx }, ctx)
23
25
  return {
24
26
  encoding: 'application/json',
25
27
  body: result,
28
+ headers: resHeaders({ labelers }),
26
29
  }
27
30
  },
28
31
  })
@@ -34,7 +37,7 @@ const skeleton = async (input: SkeletonFnInput<Context, Params>) => {
34
37
  return { blockedDids: [] }
35
38
  }
36
39
  const { blockUris, cursor } = await ctx.hydrator.dataplane.getBlocks({
37
- actorDid: params.viewer,
40
+ actorDid: params.hydrateCtx.viewer,
38
41
  cursor: params.cursor,
39
42
  limit: params.limit,
40
43
  })
@@ -53,9 +56,7 @@ const hydration = async (
53
56
  input: HydrationFnInput<Context, Params, SkeletonState>,
54
57
  ) => {
55
58
  const { ctx, params, skeleton } = input
56
- const { viewer } = params
57
- const { blockedDids } = skeleton
58
- return ctx.hydrator.hydrateProfiles(blockedDids, viewer)
59
+ return ctx.hydrator.hydrateProfiles(skeleton.blockedDids, params.hydrateCtx)
59
60
  }
60
61
 
61
62
  const presentation = (
@@ -75,7 +76,7 @@ type Context = {
75
76
  }
76
77
 
77
78
  type Params = QueryParams & {
78
- viewer: string
79
+ hydrateCtx: HydrateCtx & { viewer: string }
79
80
  }
80
81
 
81
82
  type SkeletonState = {