@atproto/bsky 0.0.220 → 0.0.221

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @atproto/bsky
2
2
 
3
+ ## 0.0.221
4
+
5
+ ### Patch Changes
6
+
7
+ - [#4747](https://github.com/bluesky-social/atproto/pull/4747) [`3b41b81`](https://github.com/bluesky-social/atproto/commit/3b41b81e27e0aba55406642c07da01c290281647) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Remove deprecated handling from `getSuggestedFollowsByActor`
8
+
9
+ - [#4767](https://github.com/bluesky-social/atproto/pull/4767) [`4ecde48`](https://github.com/bluesky-social/atproto/commit/4ecde4879ffd769fe2c7a0f1d4e3275c776114f4) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Add feature gate to enable social proof on `getSuggestedFollowsByActor`
10
+
11
+ - Updated dependencies []:
12
+ - @atproto/xrpc-server@0.10.17
13
+ - @atproto/common@0.5.15
14
+
3
15
  ## 0.0.220
4
16
 
5
17
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"getSuggestedFollowsByActor.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getSuggestedFollowsByActor.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAEhD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAY5C,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAqCvD"}
1
+ {"version":3,"file":"getSuggestedFollowsByActor.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getSuggestedFollowsByActor.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAEhD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAe5C,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAwDvD"}
@@ -12,20 +12,35 @@ function default_1(server, ctx) {
12
12
  handler: async ({ auth, params, req }) => {
13
13
  const viewer = auth.credentials.iss;
14
14
  const labelers = ctx.reqLabelers(req);
15
- const hydrateCtx = await ctx.hydrator.createContext({ labelers, viewer });
15
+ const hydrateCtx = await ctx.hydrator.createContext({
16
+ labelers,
17
+ viewer,
18
+ featureGatesMap: ctx.featureGatesClient.checkGates(['suggested_users:social_proof:enable'], {
19
+ viewer,
20
+ req,
21
+ }),
22
+ });
16
23
  const headers = (0, common_1.noUndefinedVals)({
17
24
  'accept-language': req.headers['accept-language'],
18
25
  'x-bsky-topics': Array.isArray(req.headers['x-bsky-topics'])
19
26
  ? req.headers['x-bsky-topics'].join(',')
20
27
  : req.headers['x-bsky-topics'],
21
28
  });
22
- const { headers: resultHeaders, ...result } = await getSuggestedFollowsByActor({ ...params, hydrateCtx: hydrateCtx.copy({ viewer }), headers }, ctx);
23
- const responseHeaders = (0, common_1.noUndefinedVals)({
24
- 'content-language': resultHeaders?.['content-language'],
25
- });
29
+ let output;
30
+ let responseHeaders = {};
31
+ if (!ctx.suggestionsAgent) {
32
+ output = { suggestions: [] };
33
+ }
34
+ else {
35
+ const { skeletonHeaders, ...result } = await getSuggestedFollowsByActor({ ...params, hydrateCtx: hydrateCtx.copy({ viewer }), headers }, ctx);
36
+ output = result;
37
+ responseHeaders = (0, common_1.noUndefinedVals)({
38
+ 'content-language': skeletonHeaders?.['content-language'],
39
+ });
40
+ }
26
41
  return {
27
42
  encoding: 'application/json',
28
- body: result,
43
+ body: output,
29
44
  headers: {
30
45
  ...responseHeaders,
31
46
  ...(0, util_1.resHeaders)({ labelers: hydrateCtx.labelers }),
@@ -36,38 +51,33 @@ function default_1(server, ctx) {
36
51
  }
37
52
  const skeleton = async (input) => {
38
53
  const { params, ctx } = input;
54
+ // handled above already, this branch should not be reached
55
+ if (!ctx.suggestionsAgent) {
56
+ throw new xrpc_server_1.InternalServerError('Suggestions service not configured');
57
+ }
39
58
  const [relativeToDid] = await ctx.hydrator.actor.getDids([params.actor]);
40
59
  if (!relativeToDid) {
41
60
  throw new xrpc_server_1.InvalidRequestError('Actor not found');
42
61
  }
43
- if (ctx.suggestionsAgent) {
44
- const res = await ctx.suggestionsAgent.api.app.bsky.unspecced.getSuggestionsSkeleton({
45
- viewer: params.hydrateCtx.viewer ?? undefined,
46
- relativeToDid,
47
- }, { headers: params.headers });
48
- return {
49
- isFallback: !res.data.relativeToDid,
50
- suggestedDids: res.data.actors.map((a) => a.did),
51
- recId: res.data.recId,
52
- recIdStr: res.data.recIdStr,
53
- headers: res.headers,
54
- };
55
- }
56
- else {
57
- const { dids } = await ctx.hydrator.dataplane.getFollowSuggestions({
58
- actorDid: params.hydrateCtx.viewer,
59
- relativeToDid,
60
- });
61
- return {
62
- isFallback: true,
63
- suggestedDids: dids,
64
- };
65
- }
62
+ const res = await ctx.suggestionsAgent.app.bsky.unspecced.getSuggestionsSkeleton({
63
+ viewer: params.hydrateCtx.viewer ?? undefined,
64
+ relativeToDid,
65
+ }, { headers: params.headers });
66
+ return {
67
+ recIdStr: res.data.recIdStr,
68
+ suggestedDids: res.data.actors.map((a) => a.did),
69
+ skeletonHeaders: res.headers,
70
+ };
66
71
  };
67
72
  const hydration = async (input) => {
68
73
  const { ctx, params, skeleton } = input;
69
74
  const { suggestedDids } = skeleton;
70
- return ctx.hydrator.hydrateProfiles(suggestedDids, params.hydrateCtx);
75
+ if (params.hydrateCtx.featureGatesMap.get('suggested_users:social_proof:enable')) {
76
+ return ctx.hydrator.hydrateProfilesDetailed(suggestedDids, params.hydrateCtx);
77
+ }
78
+ else {
79
+ return ctx.hydrator.hydrateProfiles(suggestedDids, params.hydrateCtx);
80
+ }
71
81
  };
72
82
  const noBlocksOrMutes = (input) => {
73
83
  const { ctx, skeleton, hydration } = input;
@@ -77,14 +87,12 @@ const noBlocksOrMutes = (input) => {
77
87
  };
78
88
  const presentation = (input) => {
79
89
  const { ctx, hydration, skeleton } = input;
80
- const { suggestedDids, headers } = skeleton;
81
- const suggestions = (0, common_1.mapDefined)(suggestedDids, (did) => ctx.views.profile(did, hydration));
90
+ const { suggestedDids, skeletonHeaders } = skeleton;
91
+ const suggestions = (0, common_1.mapDefined)(suggestedDids, (did) => ctx.views.profileKnownFollowers(did, hydration));
82
92
  return {
83
- isFallback: skeleton.isFallback,
84
- suggestions,
85
- recId: skeleton.recId,
86
93
  recIdStr: skeleton.recIdStr,
87
- headers,
94
+ suggestions,
95
+ skeletonHeaders,
88
96
  };
89
97
  };
90
98
  //# sourceMappingURL=getSuggestedFollowsByActor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"getSuggestedFollowsByActor.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getSuggestedFollowsByActor.ts"],"names":[],"mappings":";;AAkBA,4BAqCC;AAtDD,4CAA6D;AAE7D,sDAA0D;AAK1D,mDAM6B;AAE7B,wCAA0C;AAE1C,mBAAyB,MAAc,EAAE,GAAe;IACtD,MAAM,0BAA0B,GAAG,IAAA,yBAAc,EAC/C,QAAQ,EACR,SAAS,EACT,eAAe,EACf,YAAY,CACb,CAAA;IACD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,0BAA0B,CAAC;QAC/C,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,QAAQ;QAC/B,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE;YACvC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAA;YACnC,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;YACrC,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;YACzE,MAAM,OAAO,GAAG,IAAA,wBAAe,EAAC;gBAC9B,iBAAiB,EAAE,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC;gBACjD,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;oBAC1D,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;oBACxC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC;aACjC,CAAC,CAAA;YACF,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,GACzC,MAAM,0BAA0B,CAC9B,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,EAC/D,GAAG,CACJ,CAAA;YACH,MAAM,eAAe,GAAG,IAAA,wBAAe,EAAC;gBACtC,kBAAkB,EAAE,aAAa,EAAE,CAAC,kBAAkB,CAAC;aACxD,CAAC,CAAA;YACF,OAAO;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,GAAG,eAAe;oBAClB,GAAG,IAAA,iBAAU,EAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC;iBACjD;aACF,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,QAAQ,GAAG,KAAK,EAAE,KAAuC,EAAE,EAAE;IACjE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAA;IAC7B,MAAM,CAAC,aAAa,CAAC,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;IACxE,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,iCAAmB,CAAC,iBAAiB,CAAC,CAAA;IAClD,CAAC;IAED,IAAI,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACzB,MAAM,GAAG,GACP,MAAM,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,sBAAsB,CACtE;YACE,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM,IAAI,SAAS;YAC7C,aAAa;SACd,EACD,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAC5B,CAAA;QACH,OAAO;YACL,UAAU,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa;YACnC,aAAa,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;YAChD,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK;YACrB,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ;YAC3B,OAAO,EAAE,GAAG,CAAC,OAAO;SACrB,CAAA;IACH,CAAC;SAAM,CAAC;QACN,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,oBAAoB,CAAC;YACjE,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM;YAClC,aAAa;SACd,CAAC,CAAA;QACF,OAAO;YACL,UAAU,EAAE,IAAI;YAChB,aAAa,EAAE,IAAI;SACpB,CAAA;IACH,CAAC;AACH,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,KAAK,EACrB,KAAuD,EACvD,EAAE;IACF,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAA;IACvC,MAAM,EAAE,aAAa,EAAE,GAAG,QAAQ,CAAA;IAClC,OAAO,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,aAAa,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;AACvE,CAAC,CAAA;AAED,MAAM,eAAe,GAAG,CACtB,KAAmD,EACnD,EAAE;IACF,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,KAAK,CAAA;IAC1C,QAAQ,CAAC,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CACpD,CAAC,GAAG,EAAE,EAAE,CACN,CAAC,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,EAAE,SAAS,CAAC;QAC5C,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,EAAE,SAAS,CAAC,CAC9C,CAAA;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC,CAAA;AAED,MAAM,YAAY,GAAG,CACnB,KAA0D,EAC1D,EAAE;IACF,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAA;IAC1C,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAA;IAC3C,MAAM,WAAW,GAAG,IAAA,mBAAU,EAAC,aAAa,EAAE,CAAC,GAAG,EAAE,EAAE,CACpD,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAClC,CAAA;IACD,OAAO;QACL,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,WAAW;QACX,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,OAAO;KACR,CAAA;AACH,CAAC,CAAA","sourcesContent":["import { AtpAgent } from '@atproto/api'\nimport { mapDefined, noUndefinedVals } from '@atproto/common'\nimport { HeadersMap } from '@atproto/xrpc'\nimport { InvalidRequestError } from '@atproto/xrpc-server'\nimport { AppContext } from '../../../../context'\nimport { HydrateCtx, Hydrator } from '../../../../hydration/hydrator'\nimport { Server } from '../../../../lexicon'\nimport { QueryParams } from '../../../../lexicon/types/app/bsky/graph/getSuggestedFollowsByActor'\nimport {\n HydrationFnInput,\n PresentationFnInput,\n RulesFnInput,\n SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline'\nimport { Views } from '../../../../views'\nimport { resHeaders } from '../../../util'\n\nexport default function (server: Server, ctx: AppContext) {\n const getSuggestedFollowsByActor = createPipeline(\n skeleton,\n hydration,\n noBlocksOrMutes,\n presentation,\n )\n server.app.bsky.graph.getSuggestedFollowsByActor({\n auth: ctx.authVerifier.standard,\n handler: async ({ auth, params, req }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({ labelers, viewer })\n const headers = noUndefinedVals({\n 'accept-language': req.headers['accept-language'],\n 'x-bsky-topics': Array.isArray(req.headers['x-bsky-topics'])\n ? req.headers['x-bsky-topics'].join(',')\n : req.headers['x-bsky-topics'],\n })\n const { headers: resultHeaders, ...result } =\n await getSuggestedFollowsByActor(\n { ...params, hydrateCtx: hydrateCtx.copy({ viewer }), headers },\n ctx,\n )\n const responseHeaders = noUndefinedVals({\n 'content-language': resultHeaders?.['content-language'],\n })\n return {\n encoding: 'application/json',\n body: result,\n headers: {\n ...responseHeaders,\n ...resHeaders({ labelers: hydrateCtx.labelers }),\n },\n }\n },\n })\n}\n\nconst skeleton = async (input: SkeletonFnInput<Context, Params>) => {\n const { params, ctx } = input\n const [relativeToDid] = await ctx.hydrator.actor.getDids([params.actor])\n if (!relativeToDid) {\n throw new InvalidRequestError('Actor not found')\n }\n\n if (ctx.suggestionsAgent) {\n const res =\n await ctx.suggestionsAgent.api.app.bsky.unspecced.getSuggestionsSkeleton(\n {\n viewer: params.hydrateCtx.viewer ?? undefined,\n relativeToDid,\n },\n { headers: params.headers },\n )\n return {\n isFallback: !res.data.relativeToDid,\n suggestedDids: res.data.actors.map((a) => a.did),\n recId: res.data.recId,\n recIdStr: res.data.recIdStr,\n headers: res.headers,\n }\n } else {\n const { dids } = await ctx.hydrator.dataplane.getFollowSuggestions({\n actorDid: params.hydrateCtx.viewer,\n relativeToDid,\n })\n return {\n isFallback: true,\n suggestedDids: dids,\n }\n }\n}\n\nconst hydration = async (\n input: HydrationFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, params, skeleton } = input\n const { suggestedDids } = skeleton\n return ctx.hydrator.hydrateProfiles(suggestedDids, params.hydrateCtx)\n}\n\nconst noBlocksOrMutes = (\n input: RulesFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, skeleton, hydration } = input\n skeleton.suggestedDids = skeleton.suggestedDids.filter(\n (did) =>\n !ctx.views.viewerBlockExists(did, hydration) &&\n !ctx.views.viewerMuteExists(did, hydration),\n )\n return skeleton\n}\n\nconst presentation = (\n input: PresentationFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, hydration, skeleton } = input\n const { suggestedDids, headers } = skeleton\n const suggestions = mapDefined(suggestedDids, (did) =>\n ctx.views.profile(did, hydration),\n )\n return {\n isFallback: skeleton.isFallback,\n suggestions,\n recId: skeleton.recId,\n recIdStr: skeleton.recIdStr,\n headers,\n }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n suggestionsAgent: AtpAgent | undefined\n}\n\ntype Params = QueryParams & {\n hydrateCtx: HydrateCtx & { viewer: string }\n headers: HeadersMap\n}\n\ntype SkeletonState = {\n isFallback: boolean\n suggestedDids: string[]\n recId?: number\n recIdStr?: string\n headers?: HeadersMap\n}\n"]}
1
+ {"version":3,"file":"getSuggestedFollowsByActor.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getSuggestedFollowsByActor.ts"],"names":[],"mappings":"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","sourcesContent":["import { AtpAgent } from '@atproto/api'\nimport { mapDefined, noUndefinedVals } from '@atproto/common'\nimport { HeadersMap } from '@atproto/xrpc'\nimport { InternalServerError, InvalidRequestError } from '@atproto/xrpc-server'\nimport { AppContext } from '../../../../context'\nimport { HydrateCtx, Hydrator } from '../../../../hydration/hydrator'\nimport { Server } from '../../../../lexicon'\nimport {\n OutputSchema,\n QueryParams,\n} from '../../../../lexicon/types/app/bsky/graph/getSuggestedFollowsByActor'\nimport {\n HydrationFnInput,\n PresentationFnInput,\n RulesFnInput,\n SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline'\nimport { Views } from '../../../../views'\nimport { resHeaders } from '../../../util'\n\nexport default function (server: Server, ctx: AppContext) {\n const getSuggestedFollowsByActor = createPipeline(\n skeleton,\n hydration,\n noBlocksOrMutes,\n presentation,\n )\n server.app.bsky.graph.getSuggestedFollowsByActor({\n auth: ctx.authVerifier.standard,\n handler: async ({ auth, params, req }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n labelers,\n viewer,\n featureGatesMap: ctx.featureGatesClient.checkGates(\n ['suggested_users:social_proof:enable'],\n {\n viewer,\n req,\n },\n ),\n })\n const headers = noUndefinedVals({\n 'accept-language': req.headers['accept-language'],\n 'x-bsky-topics': Array.isArray(req.headers['x-bsky-topics'])\n ? req.headers['x-bsky-topics'].join(',')\n : req.headers['x-bsky-topics'],\n })\n\n let output: OutputSchema\n let responseHeaders = {}\n\n if (!ctx.suggestionsAgent) {\n output = { suggestions: [] }\n } else {\n const { skeletonHeaders, ...result } = await getSuggestedFollowsByActor(\n { ...params, hydrateCtx: hydrateCtx.copy({ viewer }), headers },\n ctx,\n )\n output = result\n responseHeaders = noUndefinedVals({\n 'content-language': skeletonHeaders?.['content-language'],\n })\n }\n\n return {\n encoding: 'application/json',\n body: output,\n headers: {\n ...responseHeaders,\n ...resHeaders({ labelers: hydrateCtx.labelers }),\n },\n }\n },\n })\n}\n\nconst skeleton = async (input: SkeletonFnInput<Context, Params>) => {\n const { params, ctx } = input\n\n // handled above already, this branch should not be reached\n if (!ctx.suggestionsAgent) {\n throw new InternalServerError('Suggestions service not configured')\n }\n\n const [relativeToDid] = await ctx.hydrator.actor.getDids([params.actor])\n if (!relativeToDid) {\n throw new InvalidRequestError('Actor not found')\n }\n\n const res =\n await ctx.suggestionsAgent.app.bsky.unspecced.getSuggestionsSkeleton(\n {\n viewer: params.hydrateCtx.viewer ?? undefined,\n relativeToDid,\n },\n { headers: params.headers },\n )\n return {\n recIdStr: res.data.recIdStr,\n suggestedDids: res.data.actors.map((a) => a.did),\n skeletonHeaders: res.headers,\n }\n}\n\nconst hydration = async (\n input: HydrationFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, params, skeleton } = input\n const { suggestedDids } = skeleton\n if (\n params.hydrateCtx.featureGatesMap.get('suggested_users:social_proof:enable')\n ) {\n return ctx.hydrator.hydrateProfilesDetailed(\n suggestedDids,\n params.hydrateCtx,\n )\n } else {\n return ctx.hydrator.hydrateProfiles(suggestedDids, params.hydrateCtx)\n }\n}\n\nconst noBlocksOrMutes = (\n input: RulesFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, skeleton, hydration } = input\n skeleton.suggestedDids = skeleton.suggestedDids.filter(\n (did) =>\n !ctx.views.viewerBlockExists(did, hydration) &&\n !ctx.views.viewerMuteExists(did, hydration),\n )\n return skeleton\n}\n\nconst presentation = (\n input: PresentationFnInput<Context, Params, SkeletonState>,\n) => {\n const { ctx, hydration, skeleton } = input\n const { suggestedDids, skeletonHeaders } = skeleton\n const suggestions = mapDefined(suggestedDids, (did) =>\n ctx.views.profileKnownFollowers(did, hydration),\n )\n return {\n recIdStr: skeleton.recIdStr,\n suggestions,\n skeletonHeaders,\n }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n suggestionsAgent: AtpAgent | undefined\n}\n\ntype Params = QueryParams & {\n hydrateCtx: HydrateCtx & { viewer: string }\n headers: HeadersMap\n}\n\ntype SkeletonState = {\n suggestedDids: string[]\n recIdStr?: string\n skeletonHeaders?: HeadersMap\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  /**
2
2
  * ADD ALL FEATURE GATES HERE.
3
3
  */
4
- export type FeatureGate = 'suggested_users:discover_agent:enable' | 'suggested_onboarding_users:discover_agent:enable' | 'threads:reply_ranking_exploration:enable' | 'search:filtering_exploration:enable';
4
+ export type FeatureGate = 'suggested_users:discover_agent:enable' | 'suggested_users:social_proof:enable' | 'suggested_onboarding_users:discover_agent:enable' | 'threads:reply_ranking_exploration:enable' | 'search:filtering_exploration:enable';
5
5
  //# sourceMappingURL=gates.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gates.d.ts","sourceRoot":"","sources":["../../src/feature-gates/gates.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,WAAW,GACnB,uCAAuC,GACvC,kDAAkD,GAClD,0CAA0C,GAC1C,qCAAqC,CAAA"}
1
+ {"version":3,"file":"gates.d.ts","sourceRoot":"","sources":["../../src/feature-gates/gates.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,WAAW,GACnB,uCAAuC,GACvC,qCAAqC,GACrC,kDAAkD,GAClD,0CAA0C,GAC1C,qCAAqC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"gates.js","sourceRoot":"","sources":["../../src/feature-gates/gates.ts"],"names":[],"mappings":";AAAA;;GAEG","sourcesContent":["/**\n * ADD ALL FEATURE GATES HERE.\n */\n\nexport type FeatureGate =\n | 'suggested_users:discover_agent:enable'\n | 'suggested_onboarding_users:discover_agent:enable'\n | 'threads:reply_ranking_exploration:enable'\n | 'search:filtering_exploration:enable'\n"]}
1
+ {"version":3,"file":"gates.js","sourceRoot":"","sources":["../../src/feature-gates/gates.ts"],"names":[],"mappings":";AAAA;;GAEG","sourcesContent":["/**\n * ADD ALL FEATURE GATES HERE.\n */\n\nexport type FeatureGate =\n | 'suggested_users:discover_agent:enable'\n | 'suggested_users:social_proof:enable'\n | 'suggested_onboarding_users:discover_agent:enable'\n | 'threads:reply_ranking_exploration:enable'\n | 'search:filtering_exploration:enable'\n"]}
@@ -5823,19 +5823,19 @@ export declare const schemaDict: {
5823
5823
  readonly ref: "lex:app.bsky.actor.defs#profileView";
5824
5824
  };
5825
5825
  };
5826
+ readonly recIdStr: {
5827
+ readonly type: "string";
5828
+ readonly description: "Snowflake for this recommendation, use when submitting recommendation events.";
5829
+ };
5826
5830
  readonly isFallback: {
5827
5831
  readonly type: "boolean";
5828
- readonly description: "If true, response has fallen-back to generic results, and is not scoped using relativeToDid";
5832
+ readonly description: "DEPRECATED, unused. Previously: if true, response has fallen-back to generic results, and is not scoped using relativeToDid";
5829
5833
  readonly default: false;
5830
5834
  };
5831
5835
  readonly recId: {
5832
5836
  readonly type: "integer";
5833
5837
  readonly description: "DEPRECATED: use recIdStr instead.";
5834
5838
  };
5835
- readonly recIdStr: {
5836
- readonly type: "string";
5837
- readonly description: "Snowflake for this recommendation, use when submitting recommendation events.";
5838
- };
5839
5839
  };
5840
5840
  };
5841
5841
  };
@@ -20143,19 +20143,19 @@ export declare const schemas: ({
20143
20143
  readonly ref: "lex:app.bsky.actor.defs#profileView";
20144
20144
  };
20145
20145
  };
20146
+ readonly recIdStr: {
20147
+ readonly type: "string";
20148
+ readonly description: "Snowflake for this recommendation, use when submitting recommendation events.";
20149
+ };
20146
20150
  readonly isFallback: {
20147
20151
  readonly type: "boolean";
20148
- readonly description: "If true, response has fallen-back to generic results, and is not scoped using relativeToDid";
20152
+ readonly description: "DEPRECATED, unused. Previously: if true, response has fallen-back to generic results, and is not scoped using relativeToDid";
20149
20153
  readonly default: false;
20150
20154
  };
20151
20155
  readonly recId: {
20152
20156
  readonly type: "integer";
20153
20157
  readonly description: "DEPRECATED: use recIdStr instead.";
20154
20158
  };
20155
- readonly recIdStr: {
20156
- readonly type: "string";
20157
- readonly description: "Snowflake for this recommendation, use when submitting recommendation events.";
20158
- };
20159
20159
  };
20160
20160
  };
20161
20161
  };
@@ -6031,19 +6031,19 @@ exports.schemaDict = {
6031
6031
  ref: 'lex:app.bsky.actor.defs#profileView',
6032
6032
  },
6033
6033
  },
6034
+ recIdStr: {
6035
+ type: 'string',
6036
+ description: 'Snowflake for this recommendation, use when submitting recommendation events.',
6037
+ },
6034
6038
  isFallback: {
6035
6039
  type: 'boolean',
6036
- description: 'If true, response has fallen-back to generic results, and is not scoped using relativeToDid',
6040
+ description: 'DEPRECATED, unused. Previously: if true, response has fallen-back to generic results, and is not scoped using relativeToDid',
6037
6041
  default: false,
6038
6042
  },
6039
6043
  recId: {
6040
6044
  type: 'integer',
6041
6045
  description: 'DEPRECATED: use recIdStr instead.',
6042
6046
  },
6043
- recIdStr: {
6044
- type: 'string',
6045
- description: 'Snowflake for this recommendation, use when submitting recommendation events.',
6046
- },
6047
6047
  },
6048
6048
  },
6049
6049
  },