@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
@@ -4,6 +4,7 @@ import { Main as RecordEmbed, View as RecordEmbedView, ViewRecord as PostEmbedVi
4
4
  import { Main as RecordWithMedia, View as RecordWithMediaView } from '../lexicon/types/app/bsky/embed/recordWithMedia';
5
5
  import { BlockedPost, GeneratorView, NotFoundPost, PostView } from '../lexicon/types/app/bsky/feed/defs';
6
6
  import { ListView } from '../lexicon/types/app/bsky/graph/defs';
7
+ import { LabelerView } from '../lexicon/types/app/bsky/labeler/defs';
7
8
  export type { Main as ImagesEmbed, View as ImagesEmbedView, } from '../lexicon/types/app/bsky/embed/images';
8
9
  export { isMain as isImagesEmbed } from '../lexicon/types/app/bsky/embed/images';
9
10
  export type { Main as ExternalEmbed, View as ExternalEmbedView, } from '../lexicon/types/app/bsky/embed/external';
@@ -19,4 +20,4 @@ export type { Notification as NotificationView } from '../lexicon/types/app/bsky
19
20
  export type Embed = ImagesEmbed | ExternalEmbed | RecordEmbed | RecordWithMedia;
20
21
  export type EmbedView = ImagesEmbedView | ExternalEmbedView | RecordEmbedView | RecordWithMediaView;
21
22
  export type MaybePostView = PostView | NotFoundPost | BlockedPost;
22
- export type RecordEmbedViewInternal = PostEmbedView | GeneratorView | ListView;
23
+ export type RecordEmbedViewInternal = PostEmbedView | GeneratorView | ListView | LabelerView;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/bsky",
3
- "version": "0.0.37",
3
+ "version": "0.0.39",
4
4
  "license": "MIT",
5
5
  "description": "Reference implementation of app.bsky App View (Bluesky API)",
6
6
  "keywords": [
@@ -39,16 +39,17 @@
39
39
  "pino": "^8.15.0",
40
40
  "pino-http": "^8.2.1",
41
41
  "sharp": "^0.32.6",
42
+ "structured-headers": "^1.0.1",
42
43
  "typed-emitter": "^2.1.0",
43
44
  "uint8arrays": "3.0.0",
44
- "@atproto/api": "^0.10.5",
45
- "@atproto/common": "^0.3.3",
45
+ "@atproto/api": "^0.11.1",
46
+ "@atproto/common": "^0.3.4",
46
47
  "@atproto/crypto": "^0.3.0",
47
- "@atproto/identity": "^0.3.2",
48
- "@atproto/lexicon": "^0.3.2",
49
- "@atproto/repo": "^0.3.8",
50
- "@atproto/syntax": "^0.2.0",
51
- "@atproto/xrpc-server": "^0.4.3"
48
+ "@atproto/identity": "^0.3.3",
49
+ "@atproto/lexicon": "^0.3.3",
50
+ "@atproto/repo": "^0.3.9",
51
+ "@atproto/syntax": "^0.2.1",
52
+ "@atproto/xrpc-server": "^0.4.4"
52
53
  },
53
54
  "devDependencies": {
54
55
  "@bufbuild/buf": "^1.28.1",
@@ -62,11 +63,11 @@
62
63
  "@types/qs": "^6.9.7",
63
64
  "axios": "^0.27.2",
64
65
  "http2-express-bridge": "^1.0.7",
65
- "@atproto/api": "^0.10.5",
66
- "@atproto/dev-env": "^0.2.37",
67
- "@atproto/lex-cli": "^0.3.1",
68
- "@atproto/pds": "^0.4.5",
69
- "@atproto/xrpc": "^0.4.2"
66
+ "@atproto/api": "^0.11.1",
67
+ "@atproto/dev-env": "^0.2.39",
68
+ "@atproto/lex-cli": "^0.3.2",
69
+ "@atproto/pds": "^0.4.7",
70
+ "@atproto/xrpc": "^0.4.3"
70
71
  },
71
72
  "scripts": {
72
73
  "codegen": "lex gen-server ./src/lexicon ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/*",
package/proto/bsky.proto CHANGED
@@ -114,6 +114,14 @@ message GetThreadGateRecordsResponse {
114
114
  repeated Record records = 1;
115
115
  }
116
116
 
117
+ message GetLabelerRecordsRequest {
118
+ repeated string uris = 1;
119
+ }
120
+
121
+ message GetLabelerRecordsResponse {
122
+ repeated Record records = 1;
123
+ }
124
+
117
125
 
118
126
  //
119
127
  // Follows
@@ -230,6 +238,8 @@ message GetCountsForUsersResponse {
230
238
  repeated int32 reposts = 2;
231
239
  repeated int32 following = 3;
232
240
  repeated int32 followers = 4;
241
+ repeated int32 lists = 5;
242
+ repeated int32 feeds = 6;
233
243
  }
234
244
 
235
245
  //
@@ -296,6 +306,7 @@ message ActorInfo {
296
306
  bool taken_down = 4;
297
307
  string takedown_ref = 5;
298
308
  google.protobuf.Timestamp tombstoned_at = 6;
309
+ bool labeler = 7;
299
310
  }
300
311
 
301
312
  message GetActorsResponse {
@@ -944,6 +955,7 @@ service Service {
944
955
  rpc GetProfileRecords(GetProfileRecordsRequest) returns (GetProfileRecordsResponse);
945
956
  rpc GetRepostRecords(GetRepostRecordsRequest) returns (GetRepostRecordsResponse);
946
957
  rpc GetThreadGateRecords(GetThreadGateRecordsRequest) returns (GetThreadGateRecordsResponse);
958
+ rpc GetLabelerRecords(GetLabelerRecordsRequest) returns (GetLabelerRecordsResponse);
947
959
 
948
960
  // Follows
949
961
  rpc GetActorFollowsActors(GetActorFollowsActorsRequest) returns (GetActorFollowsActorsResponse);
@@ -2,29 +2,35 @@ import { InvalidRequestError } from '@atproto/xrpc-server'
2
2
  import { Server } from '../../../../lexicon'
3
3
  import { QueryParams } from '../../../../lexicon/types/app/bsky/actor/getProfile'
4
4
  import AppContext from '../../../../context'
5
- import { setRepoRev } from '../../../util'
5
+ import { resHeaders } from '../../../util'
6
6
  import { createPipeline, noRules } 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
 
10
14
  export default function (server: Server, ctx: AppContext) {
11
15
  const getProfile = createPipeline(skeleton, hydration, noRules, presentation)
12
16
  server.app.bsky.actor.getProfile({
13
17
  auth: ctx.authVerifier.optionalStandardOrRole,
14
- handler: async ({ auth, params, res }) => {
15
- const { viewer, canViewTakedowns } = ctx.authVerifier.parseCreds(auth)
18
+ handler: async ({ auth, params, req }) => {
19
+ const { viewer, includeTakedowns } = ctx.authVerifier.parseCreds(auth)
20
+ const labelers = ctx.reqLabelers(req)
21
+ const hydrateCtx = { labelers, viewer, includeTakedowns }
16
22
 
17
- const result = await getProfile(
18
- { ...params, viewer, canViewTakedowns },
19
- ctx,
20
- )
23
+ const result = await getProfile({ ...params, hydrateCtx }, ctx)
21
24
 
22
25
  const repoRev = await ctx.hydrator.actor.getRepoRevSafe(viewer)
23
- setRepoRev(res, repoRev)
24
26
 
25
27
  return {
26
28
  encoding: 'application/json',
27
29
  body: result,
30
+ headers: resHeaders({
31
+ repoRev,
32
+ labelers,
33
+ }),
28
34
  }
29
35
  },
30
36
  })
@@ -48,11 +54,10 @@ const hydration = async (input: {
48
54
  skeleton: SkeletonState
49
55
  }) => {
50
56
  const { ctx, params, skeleton } = input
51
- return ctx.hydrator.hydrateProfilesDetailed(
52
- [skeleton.did],
53
- params.viewer,
54
- true,
55
- )
57
+ return ctx.hydrator.hydrateProfilesDetailed([skeleton.did], {
58
+ ...params.hydrateCtx,
59
+ includeTakedowns: true,
60
+ })
56
61
  }
57
62
 
58
63
  const presentation = (input: {
@@ -66,7 +71,7 @@ const presentation = (input: {
66
71
  if (!profile) {
67
72
  throw new InvalidRequestError('Profile not found')
68
73
  } else if (
69
- !params.canViewTakedowns &&
74
+ !params.hydrateCtx.includeTakedowns &&
70
75
  ctx.views.actorIsTakendown(skeleton.did, hydration)
71
76
  ) {
72
77
  throw new InvalidRequestError(
@@ -83,8 +88,7 @@ type Context = {
83
88
  }
84
89
 
85
90
  type Params = QueryParams & {
86
- viewer: string | null
87
- canViewTakedowns: boolean
91
+ hydrateCtx: HydrateCtx
88
92
  }
89
93
 
90
94
  type SkeletonState = { did: string }
@@ -2,26 +2,35 @@ import { mapDefined } from '@atproto/common'
2
2
  import { Server } from '../../../../lexicon'
3
3
  import { QueryParams } from '../../../../lexicon/types/app/bsky/actor/getProfiles'
4
4
  import AppContext from '../../../../context'
5
- import { setRepoRev } from '../../../util'
5
+ import { resHeaders } from '../../../util'
6
6
  import { createPipeline, noRules } 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
 
10
14
  export default function (server: Server, ctx: AppContext) {
11
15
  const getProfile = createPipeline(skeleton, hydration, noRules, presentation)
12
16
  server.app.bsky.actor.getProfiles({
13
17
  auth: ctx.authVerifier.standardOptional,
14
- handler: async ({ auth, params, res }) => {
18
+ handler: async ({ auth, params, req }) => {
15
19
  const viewer = auth.credentials.iss
20
+ const labelers = ctx.reqLabelers(req)
21
+ const hydrateCtx = { viewer, labelers }
16
22
 
17
- const result = await getProfile({ ...params, viewer }, ctx)
23
+ const result = await getProfile({ ...params, hydrateCtx }, ctx)
18
24
 
19
25
  const repoRev = await ctx.hydrator.actor.getRepoRevSafe(viewer)
20
- setRepoRev(res, repoRev)
21
26
 
22
27
  return {
23
28
  encoding: 'application/json',
24
29
  body: result,
30
+ headers: resHeaders({
31
+ repoRev,
32
+ labelers,
33
+ }),
25
34
  }
26
35
  },
27
36
  })
@@ -42,7 +51,7 @@ const hydration = async (input: {
42
51
  skeleton: SkeletonState
43
52
  }) => {
44
53
  const { ctx, params, skeleton } = input
45
- return ctx.hydrator.hydrateProfilesDetailed(skeleton.dids, params.viewer)
54
+ return ctx.hydrator.hydrateProfilesDetailed(skeleton.dids, params.hydrateCtx)
46
55
  }
47
56
 
48
57
  const presentation = (input: {
@@ -64,7 +73,7 @@ type Context = {
64
73
  }
65
74
 
66
75
  type Params = QueryParams & {
67
- viewer: string | null
76
+ hydrateCtx: HydrateCtx
68
77
  }
69
78
 
70
79
  type SkeletonState = { dids: string[] }
@@ -3,10 +3,15 @@ import AppContext from '../../../../context'
3
3
  import { Server } from '../../../../lexicon'
4
4
  import { QueryParams } from '../../../../lexicon/types/app/bsky/actor/getSuggestions'
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'
14
+ import { resHeaders } from '../../../util'
10
15
 
11
16
  export default function (server: Server, ctx: AppContext) {
12
17
  const getSuggestions = createPipeline(
@@ -17,13 +22,16 @@ export default function (server: Server, ctx: AppContext) {
17
22
  )
18
23
  server.app.bsky.actor.getSuggestions({
19
24
  auth: ctx.authVerifier.standardOptional,
20
- handler: async ({ params, auth }) => {
25
+ handler: async ({ params, auth, req }) => {
21
26
  const viewer = auth.credentials.iss
22
- const result = await getSuggestions({ ...params, viewer }, ctx)
27
+ const labelers = ctx.reqLabelers(req)
28
+ const hydrateCtx = { viewer, labelers }
29
+ const result = await getSuggestions({ ...params, hydrateCtx }, ctx)
23
30
 
24
31
  return {
25
32
  encoding: 'application/json',
26
33
  body: result,
34
+ headers: resHeaders({ labelers }),
27
35
  }
28
36
  },
29
37
  })
@@ -34,19 +42,20 @@ const skeleton = async (input: {
34
42
  params: Params
35
43
  }): Promise<Skeleton> => {
36
44
  const { ctx, params } = input
45
+ const viewer = params.hydrateCtx.viewer
37
46
  // @NOTE for appview swap moving to rkey-based cursors which are somewhat permissive, should not hard-break pagination
38
47
  const suggestions = await ctx.dataplane.getFollowSuggestions({
39
- actorDid: params.viewer ?? undefined,
48
+ actorDid: viewer ?? undefined,
40
49
  cursor: params.cursor,
41
50
  limit: params.limit,
42
51
  })
43
52
  let dids = suggestions.dids
44
- if (params.viewer !== null) {
53
+ if (viewer !== null) {
45
54
  const follows = await ctx.dataplane.getActorFollowsActors({
46
- actorDid: params.viewer,
55
+ actorDid: viewer,
47
56
  targetDids: dids,
48
57
  })
49
- dids = dids.filter((did, i) => !follows.uris[i] && did !== params.viewer)
58
+ dids = dids.filter((did, i) => !follows.uris[i] && did !== viewer)
50
59
  }
51
60
  return { dids, cursor: parseString(suggestions.cursor) }
52
61
  }
@@ -57,11 +66,7 @@ const hydration = async (input: {
57
66
  skeleton: Skeleton
58
67
  }) => {
59
68
  const { ctx, params, skeleton } = input
60
- return ctx.hydrator.hydrateProfilesDetailed(
61
- skeleton.dids,
62
- params.viewer,
63
- true,
64
- )
69
+ return ctx.hydrator.hydrateProfilesDetailed(skeleton.dids, params.hydrateCtx)
65
70
  }
66
71
 
67
72
  const noBlocksOrMutes = (input: {
@@ -102,7 +107,7 @@ type Context = {
102
107
  }
103
108
 
104
109
  type Params = QueryParams & {
105
- viewer: string | null
110
+ hydrateCtx: HydrateCtx
106
111
  }
107
112
 
108
113
  type Skeleton = { dids: string[]; cursor?: string }
@@ -10,10 +10,11 @@ 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
+ import { resHeaders } from '../../../util'
17
18
 
18
19
  export default function (server: Server, ctx: AppContext) {
19
20
  const searchActors = createPipeline(
@@ -24,12 +25,15 @@ export default function (server: Server, ctx: AppContext) {
24
25
  )
25
26
  server.app.bsky.actor.searchActors({
26
27
  auth: ctx.authVerifier.standardOptional,
27
- handler: async ({ auth, params }) => {
28
+ handler: async ({ auth, params, req }) => {
28
29
  const viewer = auth.credentials.iss
29
- const results = await searchActors({ ...params, viewer }, ctx)
30
+ const labelers = ctx.reqLabelers(req)
31
+ const hydrateCtx = { viewer, labelers }
32
+ const results = await searchActors({ ...params, hydrateCtx }, ctx)
30
33
  return {
31
34
  encoding: 'application/json',
32
35
  body: results,
36
+ headers: resHeaders({ labelers }),
33
37
  }
34
38
  },
35
39
  })
@@ -71,7 +75,7 @@ const hydration = async (
71
75
  inputs: HydrationFnInput<Context, Params, Skeleton>,
72
76
  ) => {
73
77
  const { ctx, params, skeleton } = inputs
74
- return ctx.hydrator.hydrateProfiles(skeleton.dids, params.viewer)
78
+ return ctx.hydrator.hydrateProfiles(skeleton.dids, params.hydrateCtx)
75
79
  }
76
80
 
77
81
  const noBlocks = (inputs: RulesFnInput<Context, Params, Skeleton>) => {
@@ -102,7 +106,7 @@ type Context = {
102
106
  searchAgent?: AtpAgent
103
107
  }
104
108
 
105
- type Params = QueryParams & { viewer: string | null }
109
+ type Params = QueryParams & { hydrateCtx: HydrateCtx }
106
110
 
107
111
  type Skeleton = {
108
112
  dids: string[]
@@ -10,10 +10,11 @@ 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
+ import { resHeaders } from '../../../util'
17
18
 
18
19
  export default function (server: Server, ctx: AppContext) {
19
20
  const searchActorsTypeahead = createPipeline(
@@ -24,12 +25,18 @@ export default function (server: Server, ctx: AppContext) {
24
25
  )
25
26
  server.app.bsky.actor.searchActorsTypeahead({
26
27
  auth: ctx.authVerifier.standardOptional,
27
- handler: async ({ params, auth }) => {
28
+ handler: async ({ params, auth, req }) => {
28
29
  const viewer = auth.credentials.iss
29
- const results = await searchActorsTypeahead({ ...params, viewer }, ctx)
30
+ const labelers = ctx.reqLabelers(req)
31
+ const hydrateCtx = { labelers, viewer }
32
+ const results = await searchActorsTypeahead(
33
+ { ...params, hydrateCtx },
34
+ ctx,
35
+ )
30
36
  return {
31
37
  encoding: 'application/json',
32
38
  body: results,
39
+ headers: resHeaders({ labelers }),
33
40
  }
34
41
  },
35
42
  })
@@ -70,7 +77,7 @@ const hydration = async (
70
77
  inputs: HydrationFnInput<Context, Params, Skeleton>,
71
78
  ) => {
72
79
  const { ctx, params, skeleton } = inputs
73
- return ctx.hydrator.hydrateProfilesBasic(skeleton.dids, params.viewer)
80
+ return ctx.hydrator.hydrateProfilesBasic(skeleton.dids, params.hydrateCtx)
74
81
  }
75
82
 
76
83
  const noBlocks = (inputs: RulesFnInput<Context, Params, Skeleton>) => {
@@ -100,7 +107,7 @@ type Context = {
100
107
  searchAgent?: AtpAgent
101
108
  }
102
109
 
103
- type Params = QueryParams & { viewer: string | null }
110
+ type Params = QueryParams & { hydrateCtx: HydrateCtx }
104
111
 
105
112
  type Skeleton = {
106
113
  dids: string[]
@@ -4,11 +4,15 @@ import { Server } from '../../../../lexicon'
4
4
  import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getActorFeeds'
5
5
  import AppContext from '../../../../context'
6
6
  import { createPipeline, noRules } 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 { DataPlaneClient } from '../../../../data-plane'
10
14
  import { parseString } from '../../../../hydration/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 getActorFeeds = createPipeline(
@@ -19,12 +23,15 @@ export default function (server: Server, ctx: AppContext) {
19
23
  )
20
24
  server.app.bsky.feed.getActorFeeds({
21
25
  auth: ctx.authVerifier.standardOptional,
22
- handler: async ({ auth, params }) => {
26
+ handler: async ({ auth, params, req }) => {
23
27
  const viewer = auth.credentials.iss
24
- const result = await getActorFeeds({ ...params, viewer }, ctx)
28
+ const labelers = ctx.reqLabelers(req)
29
+ const hydrateCtx = { labelers, viewer }
30
+ const result = await getActorFeeds({ ...params, hydrateCtx }, ctx)
25
31
  return {
26
32
  encoding: 'application/json',
27
33
  body: result,
34
+ headers: resHeaders({ labelers }),
28
35
  }
29
36
  },
30
37
  })
@@ -59,7 +66,10 @@ const hydration = async (inputs: {
59
66
  skeleton: Skeleton
60
67
  }) => {
61
68
  const { ctx, params, skeleton } = inputs
62
- return await ctx.hydrator.hydrateFeedGens(skeleton.feedUris, params.viewer)
69
+ return await ctx.hydrator.hydrateFeedGens(
70
+ skeleton.feedUris,
71
+ params.hydrateCtx,
72
+ )
63
73
  }
64
74
 
65
75
  const presentation = (inputs: {
@@ -83,7 +93,7 @@ type Context = {
83
93
  dataplane: DataPlaneClient
84
94
  }
85
95
 
86
- type Params = QueryParams & { viewer: string | null }
96
+ type Params = QueryParams & { hydrateCtx: HydrateCtx }
87
97
 
88
98
  type Skeleton = {
89
99
  feedUris: string[]
@@ -3,9 +3,13 @@ import { mapDefined } from '@atproto/common'
3
3
  import { Server } from '../../../../lexicon'
4
4
  import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getActorLikes'
5
5
  import AppContext from '../../../../context'
6
- import { clearlyBadCursor, setRepoRev } from '../../../util'
6
+ import { clearlyBadCursor, resHeaders } from '../../../util'
7
7
  import { createPipeline } from '../../../../pipeline'
8
- import { HydrationState, Hydrator } from '../../../../hydration/hydrator'
8
+ import {
9
+ HydrateCtx,
10
+ HydrationState,
11
+ Hydrator,
12
+ } from '../../../../hydration/hydrator'
9
13
  import { Views } from '../../../../views'
10
14
  import { DataPlaneClient } from '../../../../data-plane'
11
15
  import { parseString } from '../../../../hydration/util'
@@ -21,17 +25,22 @@ export default function (server: Server, ctx: AppContext) {
21
25
  )
22
26
  server.app.bsky.feed.getActorLikes({
23
27
  auth: ctx.authVerifier.standardOptional,
24
- handler: async ({ params, auth, res }) => {
28
+ handler: async ({ params, auth, req }) => {
25
29
  const viewer = auth.credentials.iss
30
+ const labelers = ctx.reqLabelers(req)
31
+ const hydrateCtx = { labelers, viewer }
26
32
 
27
- const result = await getActorLikes({ ...params, viewer }, ctx)
33
+ const result = await getActorLikes({ ...params, hydrateCtx }, ctx)
28
34
 
29
35
  const repoRev = await ctx.hydrator.actor.getRepoRevSafe(viewer)
30
- setRepoRev(res, repoRev)
31
36
 
32
37
  return {
33
38
  encoding: 'application/json',
34
39
  body: result,
40
+ headers: resHeaders({
41
+ repoRev,
42
+ labelers,
43
+ }),
35
44
  }
36
45
  },
37
46
  })
@@ -42,7 +51,8 @@ const skeleton = async (inputs: {
42
51
  params: Params
43
52
  }): Promise<Skeleton> => {
44
53
  const { ctx, params } = inputs
45
- const { actor, limit, cursor, viewer } = params
54
+ const { actor, limit, cursor } = params
55
+ const viewer = params.hydrateCtx.viewer
46
56
  if (clearlyBadCursor(cursor)) {
47
57
  return { items: [] }
48
58
  }
@@ -71,7 +81,7 @@ const hydration = async (inputs: {
71
81
  skeleton: Skeleton
72
82
  }) => {
73
83
  const { ctx, params, skeleton } = inputs
74
- return await ctx.hydrator.hydrateFeedItems(skeleton.items, params.viewer)
84
+ return await ctx.hydrator.hydrateFeedItems(skeleton.items, params.hydrateCtx)
75
85
  }
76
86
 
77
87
  const noPostBlocks = (inputs: {
@@ -108,7 +118,7 @@ type Context = {
108
118
  dataplane: DataPlaneClient
109
119
  }
110
120
 
111
- type Params = QueryParams & { viewer: string | null }
121
+ type Params = QueryParams & { hydrateCtx: HydrateCtx }
112
122
 
113
123
  type Skeleton = {
114
124
  items: FeedItem[]
@@ -3,9 +3,10 @@ import { InvalidRequestError } from '@atproto/xrpc-server'
3
3
  import { Server } from '../../../../lexicon'
4
4
  import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/getAuthorFeed'
5
5
  import AppContext from '../../../../context'
6
- import { clearlyBadCursor, setRepoRev } from '../../../util'
6
+ import { clearlyBadCursor, resHeaders } from '../../../util'
7
7
  import { createPipeline } from '../../../../pipeline'
8
8
  import {
9
+ HydrateCtx,
9
10
  HydrationState,
10
11
  Hydrator,
11
12
  mergeStates,
@@ -26,20 +27,22 @@ export default function (server: Server, ctx: AppContext) {
26
27
  )
27
28
  server.app.bsky.feed.getAuthorFeed({
28
29
  auth: ctx.authVerifier.optionalStandardOrRole,
29
- handler: async ({ params, auth, res }) => {
30
- const { viewer, canViewTakedowns } = ctx.authVerifier.parseCreds(auth)
30
+ handler: async ({ params, auth, req }) => {
31
+ const { viewer, includeTakedowns } = ctx.authVerifier.parseCreds(auth)
32
+ const labelers = ctx.reqLabelers(req)
33
+ const hydrateCtx = { labelers, viewer, includeTakedowns }
31
34
 
32
- const result = await getAuthorFeed(
33
- { ...params, viewer, includeTakedowns: canViewTakedowns },
34
- ctx,
35
- )
35
+ const result = await getAuthorFeed({ ...params, hydrateCtx }, ctx)
36
36
 
37
37
  const repoRev = await ctx.hydrator.actor.getRepoRevSafe(viewer)
38
- setRepoRev(res, repoRev)
39
38
 
40
39
  return {
41
40
  encoding: 'application/json',
42
41
  body: result,
42
+ headers: resHeaders({
43
+ repoRev,
44
+ labelers,
45
+ }),
43
46
  }
44
47
  },
45
48
  })
@@ -63,7 +66,7 @@ export const skeleton = async (inputs: {
63
66
  }
64
67
  const actors = await ctx.hydrator.actor.getActors(
65
68
  [did],
66
- params.includeTakedowns,
69
+ params.hydrateCtx.includeTakedowns,
67
70
  )
68
71
  const actor = actors.get(did)
69
72
  if (!actor) {
@@ -96,15 +99,9 @@ const hydration = async (inputs: {
96
99
  skeleton: Skeleton
97
100
  }): Promise<HydrationState> => {
98
101
  const { ctx, params, skeleton } = inputs
99
- const [feedPostState, profileViewerState = {}] = await Promise.all([
100
- ctx.hydrator.hydrateFeedItems(
101
- skeleton.items,
102
- params.viewer,
103
- params.includeTakedowns,
104
- ),
105
- params.viewer
106
- ? ctx.hydrator.hydrateProfileViewers([skeleton.actor.did], params.viewer)
107
- : undefined,
102
+ const [feedPostState, profileViewerState] = await Promise.all([
103
+ ctx.hydrator.hydrateFeedItems(skeleton.items, params.hydrateCtx),
104
+ ctx.hydrator.hydrateProfileViewers([skeleton.actor.did], params.hydrateCtx),
108
105
  ])
109
106
  return mergeStates(feedPostState, profileViewerState)
110
107
  }
@@ -157,7 +154,9 @@ type Context = {
157
154
  dataplane: DataPlaneClient
158
155
  }
159
156
 
160
- type Params = QueryParams & { viewer: string | null; includeTakedowns: boolean }
157
+ type Params = QueryParams & {
158
+ hydrateCtx: HydrateCtx
159
+ }
161
160
 
162
161
  type Skeleton = {
163
162
  actor: Actor