@atproto/bsky 0.1.1 → 0.1.4
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 +44 -0
- package/dist/api/app/bsky/actor/getSuggestions.d.ts.map +1 -1
- package/dist/api/app/bsky/actor/getSuggestions.js +9 -3
- package/dist/api/app/bsky/actor/getSuggestions.js.map +1 -1
- package/dist/api/app/bsky/feed/getFeed.d.ts.map +1 -1
- package/dist/api/app/bsky/feed/getFeed.js +44 -15
- package/dist/api/app/bsky/feed/getFeed.js.map +1 -1
- package/dist/api/app/bsky/graph/getSuggestedFollowsByActor.d.ts.map +1 -1
- package/dist/api/app/bsky/graph/getSuggestedFollowsByActor.js +7 -3
- package/dist/api/app/bsky/graph/getSuggestedFollowsByActor.js.map +1 -1
- package/dist/api/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.d.ts.map +1 -1
- package/dist/api/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.js +13 -4
- package/dist/api/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.js.map +1 -1
- package/dist/api/app/bsky/unspecced/getSuggestedFeeds.d.ts.map +1 -1
- package/dist/api/app/bsky/unspecced/getSuggestedFeeds.js +12 -4
- package/dist/api/app/bsky/unspecced/getSuggestedFeeds.js.map +1 -1
- package/dist/api/app/bsky/unspecced/getSuggestedOnboardingUsers.d.ts.map +1 -1
- package/dist/api/app/bsky/unspecced/getSuggestedOnboardingUsers.js +10 -3
- package/dist/api/app/bsky/unspecced/getSuggestedOnboardingUsers.js.map +1 -1
- package/dist/api/app/bsky/unspecced/getSuggestedStarterPacks.d.ts.map +1 -1
- package/dist/api/app/bsky/unspecced/getSuggestedStarterPacks.js +13 -4
- package/dist/api/app/bsky/unspecced/getSuggestedStarterPacks.js.map +1 -1
- package/dist/api/app/bsky/unspecced/getSuggestedUsers.js +18 -0
- package/dist/api/app/bsky/unspecced/getSuggestedUsers.js.map +1 -1
- package/dist/api/app/bsky/unspecced/getSuggestedUsersForDiscover.js +17 -0
- package/dist/api/app/bsky/unspecced/getSuggestedUsersForDiscover.js.map +1 -1
- package/dist/api/app/bsky/unspecced/getSuggestedUsersForExplore.js +18 -0
- package/dist/api/app/bsky/unspecced/getSuggestedUsersForExplore.js.map +1 -1
- package/dist/api/app/bsky/unspecced/getSuggestedUsersForSeeMore.js +18 -0
- package/dist/api/app/bsky/unspecced/getSuggestedUsersForSeeMore.js.map +1 -1
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +22 -0
- package/dist/config.js.map +1 -1
- package/dist/data-plane/server/routes/atmosphere.d.ts +5 -0
- package/dist/data-plane/server/routes/atmosphere.d.ts.map +1 -0
- package/dist/data-plane/server/routes/atmosphere.js +24 -0
- package/dist/data-plane/server/routes/atmosphere.js.map +1 -0
- package/dist/data-plane/server/routes/index.js +2 -2
- package/dist/data-plane/server/routes/index.js.map +1 -1
- package/dist/feature-gates/gates.d.ts +10 -0
- package/dist/feature-gates/gates.d.ts.map +1 -1
- package/dist/feature-gates/gates.js +10 -0
- package/dist/feature-gates/gates.js.map +1 -1
- package/dist/feature-gates/index.js +2 -2
- package/dist/feature-gates/index.js.map +1 -1
- package/dist/hydration/external.d.ts +65 -2
- package/dist/hydration/external.d.ts.map +1 -1
- package/dist/hydration/external.js +220 -29
- package/dist/hydration/external.js.map +1 -1
- package/dist/hydration/hydrator.d.ts.map +1 -1
- package/dist/hydration/hydrator.js +7 -7
- package/dist/hydration/hydrator.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/lexicons/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.defs.d.ts +2 -0
- package/dist/lexicons/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.defs.js +1 -0
- package/dist/lexicons/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/unspecced/getOnboardingSuggestedStarterPacksSkeleton.defs.d.ts +2 -0
- package/dist/lexicons/app/bsky/unspecced/getOnboardingSuggestedStarterPacksSkeleton.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/unspecced/getOnboardingSuggestedStarterPacksSkeleton.defs.js +1 -0
- package/dist/lexicons/app/bsky/unspecced/getOnboardingSuggestedStarterPacksSkeleton.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/unspecced/getSuggestedFeeds.defs.d.ts +2 -0
- package/dist/lexicons/app/bsky/unspecced/getSuggestedFeeds.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/unspecced/getSuggestedFeeds.defs.js +1 -0
- package/dist/lexicons/app/bsky/unspecced/getSuggestedFeeds.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/unspecced/getSuggestedFeedsSkeleton.defs.d.ts +2 -0
- package/dist/lexicons/app/bsky/unspecced/getSuggestedFeedsSkeleton.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/unspecced/getSuggestedFeedsSkeleton.defs.js +1 -0
- package/dist/lexicons/app/bsky/unspecced/getSuggestedFeedsSkeleton.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/unspecced/getSuggestedStarterPacks.defs.d.ts +2 -0
- package/dist/lexicons/app/bsky/unspecced/getSuggestedStarterPacks.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/unspecced/getSuggestedStarterPacks.defs.js +1 -0
- package/dist/lexicons/app/bsky/unspecced/getSuggestedStarterPacks.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/unspecced/getSuggestedStarterPacksSkeleton.defs.d.ts +2 -0
- package/dist/lexicons/app/bsky/unspecced/getSuggestedStarterPacksSkeleton.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/unspecced/getSuggestedStarterPacksSkeleton.defs.js +1 -0
- package/dist/lexicons/app/bsky/unspecced/getSuggestedStarterPacksSkeleton.defs.js.map +1 -1
- package/dist/lexicons/tools/ozone/inbox/defs.defs.d.ts +110 -6
- package/dist/lexicons/tools/ozone/inbox/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/tools/ozone/inbox/defs.defs.js +90 -2
- package/dist/lexicons/tools/ozone/inbox/defs.defs.js.map +1 -1
- package/dist/lexicons/tools/ozone/inbox/getAccountStatus.d.ts +3 -0
- package/dist/lexicons/tools/ozone/inbox/getAccountStatus.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getAccountStatus.defs.d.ts +50 -0
- package/dist/lexicons/tools/ozone/inbox/getAccountStatus.defs.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getAccountStatus.defs.js +22 -0
- package/dist/lexicons/tools/ozone/inbox/getAccountStatus.defs.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getAccountStatus.js +6 -0
- package/dist/lexicons/tools/ozone/inbox/getAccountStatus.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getActionedSubject.d.ts +3 -0
- package/dist/lexicons/tools/ozone/inbox/getActionedSubject.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getActionedSubject.defs.d.ts +35 -0
- package/dist/lexicons/tools/ozone/inbox/getActionedSubject.defs.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getActionedSubject.defs.js +23 -0
- package/dist/lexicons/tools/ozone/inbox/getActionedSubject.defs.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getActionedSubject.js +6 -0
- package/dist/lexicons/tools/ozone/inbox/getActionedSubject.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getNotificationPreferences.d.ts +3 -0
- package/dist/lexicons/tools/ozone/inbox/getNotificationPreferences.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getNotificationPreferences.defs.d.ts +28 -0
- package/dist/lexicons/tools/ozone/inbox/getNotificationPreferences.defs.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getNotificationPreferences.defs.js +18 -0
- package/dist/lexicons/tools/ozone/inbox/getNotificationPreferences.defs.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getNotificationPreferences.js +6 -0
- package/dist/lexicons/tools/ozone/inbox/getNotificationPreferences.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getReport.d.ts +3 -0
- package/dist/lexicons/tools/ozone/inbox/getReport.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getReport.defs.d.ts +75 -0
- package/dist/lexicons/tools/ozone/inbox/getReport.defs.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getReport.defs.js +52 -0
- package/dist/lexicons/tools/ozone/inbox/getReport.defs.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getReport.js +6 -0
- package/dist/lexicons/tools/ozone/inbox/getReport.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getUnreadCount.d.ts +3 -0
- package/dist/lexicons/tools/ozone/inbox/getUnreadCount.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getUnreadCount.defs.d.ts +43 -0
- package/dist/lexicons/tools/ozone/inbox/getUnreadCount.defs.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getUnreadCount.defs.js +28 -0
- package/dist/lexicons/tools/ozone/inbox/getUnreadCount.defs.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/getUnreadCount.js +6 -0
- package/dist/lexicons/tools/ozone/inbox/getUnreadCount.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/listActionedSubjects.d.ts +3 -0
- package/dist/lexicons/tools/ozone/inbox/listActionedSubjects.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/listActionedSubjects.defs.d.ts +41 -0
- package/dist/lexicons/tools/ozone/inbox/listActionedSubjects.defs.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/listActionedSubjects.defs.js +33 -0
- package/dist/lexicons/tools/ozone/inbox/listActionedSubjects.defs.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/listActionedSubjects.js +6 -0
- package/dist/lexicons/tools/ozone/inbox/listActionedSubjects.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/listNotifications.d.ts +3 -0
- package/dist/lexicons/tools/ozone/inbox/listNotifications.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/listNotifications.defs.d.ts +48 -0
- package/dist/lexicons/tools/ozone/inbox/listNotifications.defs.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/listNotifications.defs.js +31 -0
- package/dist/lexicons/tools/ozone/inbox/listNotifications.defs.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/listNotifications.js +6 -0
- package/dist/lexicons/tools/ozone/inbox/listNotifications.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/listReports.d.ts +3 -0
- package/dist/lexicons/tools/ozone/inbox/listReports.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/listReports.defs.d.ts +72 -0
- package/dist/lexicons/tools/ozone/inbox/listReports.defs.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/listReports.defs.js +57 -0
- package/dist/lexicons/tools/ozone/inbox/listReports.defs.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/listReports.js +6 -0
- package/dist/lexicons/tools/ozone/inbox/listReports.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/putNotificationPreferences.d.ts +3 -0
- package/dist/lexicons/tools/ozone/inbox/putNotificationPreferences.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/putNotificationPreferences.defs.d.ts +27 -0
- package/dist/lexicons/tools/ozone/inbox/putNotificationPreferences.defs.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/putNotificationPreferences.defs.js +19 -0
- package/dist/lexicons/tools/ozone/inbox/putNotificationPreferences.defs.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/putNotificationPreferences.js +6 -0
- package/dist/lexicons/tools/ozone/inbox/putNotificationPreferences.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/updateSeen.d.ts +3 -0
- package/dist/lexicons/tools/ozone/inbox/updateSeen.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/updateSeen.defs.d.ts +40 -0
- package/dist/lexicons/tools/ozone/inbox/updateSeen.defs.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/updateSeen.defs.js +21 -0
- package/dist/lexicons/tools/ozone/inbox/updateSeen.defs.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox/updateSeen.js +6 -0
- package/dist/lexicons/tools/ozone/inbox/updateSeen.js.map +1 -0
- package/dist/lexicons/tools/ozone/inbox.d.ts +10 -0
- package/dist/lexicons/tools/ozone/inbox.d.ts.map +1 -1
- package/dist/lexicons/tools/ozone/inbox.js +10 -0
- package/dist/lexicons/tools/ozone/inbox.js.map +1 -1
- package/dist/lexicons/tools/ozone/moderation/defs.defs.d.ts +10 -0
- package/dist/lexicons/tools/ozone/moderation/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/tools/ozone/moderation/defs.defs.js +5 -0
- package/dist/lexicons/tools/ozone/moderation/defs.defs.js.map +1 -1
- package/dist/lexicons/tools/ozone/server/getCapabilities.d.ts +3 -0
- package/dist/lexicons/tools/ozone/server/getCapabilities.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/server/getCapabilities.defs.d.ts +26 -0
- package/dist/lexicons/tools/ozone/server/getCapabilities.defs.d.ts.map +1 -0
- package/dist/lexicons/tools/ozone/server/getCapabilities.defs.js +22 -0
- package/dist/lexicons/tools/ozone/server/getCapabilities.defs.js.map +1 -0
- package/dist/lexicons/tools/ozone/server/getCapabilities.js +6 -0
- package/dist/lexicons/tools/ozone/server/getCapabilities.js.map +1 -0
- package/dist/lexicons/tools/ozone/server.d.ts +1 -0
- package/dist/lexicons/tools/ozone/server.d.ts.map +1 -1
- package/dist/lexicons/tools/ozone/server.js +1 -0
- package/dist/lexicons/tools/ozone/server.js.map +1 -1
- package/dist/proto/bsky_connect.d.ts +57 -21
- package/dist/proto/bsky_connect.d.ts.map +1 -1
- package/dist/proto/bsky_connect.js +57 -21
- package/dist/proto/bsky_connect.js.map +1 -1
- package/dist/proto/bsky_pb.d.ts +361 -72
- package/dist/proto/bsky_pb.d.ts.map +1 -1
- package/dist/proto/bsky_pb.js +529 -70
- package/dist/proto/bsky_pb.js.map +1 -1
- package/dist/util/standard-site.d.ts +0 -12
- package/dist/util/standard-site.d.ts.map +1 -1
- package/dist/util/standard-site.js +0 -14
- package/dist/util/standard-site.js.map +1 -1
- package/package.json +8 -8
- package/dist/data-plane/server/routes/site-standard.d.ts +0 -6
- package/dist/data-plane/server/routes/site-standard.d.ts.map +0 -1
- package/dist/data-plane/server/routes/site-standard.js +0 -9
- package/dist/data-plane/server/routes/site-standard.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# @atproto/bsky
|
|
2
2
|
|
|
3
|
+
## 0.1.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`3013430`](https://github.com/bluesky-social/atproto/commit/3013430ed7433edd4c70d2970428d0ab803f6e85), [`a044af7`](https://github.com/bluesky-social/atproto/commit/a044af7bd7b522ca51229d7686f5b6413be6eee7), [`38b10d1`](https://github.com/bluesky-social/atproto/commit/38b10d1b870a6a8f5da0eff32a136caadadd0184)]:
|
|
8
|
+
- @atproto/api@0.24.0
|
|
9
|
+
- @atproto-labs/opentelemetry-node@0.3.1
|
|
10
|
+
|
|
11
|
+
## 0.1.3
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [#5598](https://github.com/bluesky-social/atproto/pull/5598) [`6570e75`](https://github.com/bluesky-social/atproto/commit/6570e750752eeabc8d81f9571d1dff378921e42c) Thanks [@blackmichael](https://github.com/blackmichael)! - Hydrate site.standard records through the generic record dataplane RPCs, resolving document publications with a second lookup, and remove the site.standard-specific dataplane RPCs.
|
|
16
|
+
|
|
17
|
+
## 0.1.2
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- [#5539](https://github.com/bluesky-social/atproto/pull/5539) [`3312992`](https://github.com/bluesky-social/atproto/commit/3312992fe2cb7ebc009fe4b1f4cc6bc7518b19db) Thanks [@ds-boyce](https://github.com/ds-boyce)! - Route suggested feed and starter pack skeleton requests to Iris when their v2 gates are enabled.
|
|
22
|
+
|
|
23
|
+
- [#5596](https://github.com/bluesky-social/atproto/pull/5596) [`8fbdf78`](https://github.com/bluesky-social/atproto/commit/8fbdf7885af60020cf218cef2f6d92923b38c864) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Share generic record key helpers across external record hydration.
|
|
24
|
+
|
|
25
|
+
- [#5549](https://github.com/bluesky-social/atproto/pull/5549) [`a3bf283`](https://github.com/bluesky-social/atproto/commit/a3bf283c1ae1de683ff04872ff022035d21f9efc) Thanks [@ds-boyce](https://github.com/ds-boyce)! - Read device and session identifiers from the `x-atproto-*` request headers.
|
|
26
|
+
|
|
27
|
+
- [#5602](https://github.com/bluesky-social/atproto/pull/5602) [`2ac7cb5`](https://github.com/bluesky-social/atproto/commit/2ac7cb5dff0a443ff04220abb6e84821687f61d1) Thanks [@iwsmith](https://github.com/iwsmith)! - Gate each iris-served Discover feed separately: with-friends, thevids, mutuals, bsky-team, best-of-follows, and followpics get their own `iris:feed:<feed>:enable` gates, while whats-hot and any other allowlisted feed keep the original `iris:feed:enable` gate.
|
|
28
|
+
|
|
29
|
+
- [#5605](https://github.com/bluesky-social/atproto/pull/5605) [`cb81a0f`](https://github.com/bluesky-social/atproto/commit/cb81a0f43fd1707d6a4722de37f25f1228a7390c) Thanks [@iwsmith](https://github.com/iwsmith)! - Route user-suggestion endpoints to Iris behind the `suggested_users:iris:enable` feature gate. When enabled, `getSuggestedUsers`, `getSuggestedUsersForDiscover`, `getSuggestedUsersForExplore`, `getSuggestedUsersForSeeMore`, `getSuggestedOnboardingUsers`, `getSuggestions`, and `getSuggestedFollowsByActor` fetch their skeletons from Iris instead of seeemore. `getSuggestions` still falls back to the dataplane when Iris is not configured, and `getSuggestedFollowsByActor` returns an empty list.
|
|
30
|
+
|
|
31
|
+
- [#5596](https://github.com/bluesky-social/atproto/pull/5596) [`8fbdf78`](https://github.com/bluesky-social/atproto/commit/8fbdf7885af60020cf218cef2f6d92923b38c864) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Add external hydration for generic records, Atmosphere timelines, and backlinks.
|
|
32
|
+
|
|
33
|
+
- [#5596](https://github.com/bluesky-social/atproto/pull/5596) [`8fbdf78`](https://github.com/bluesky-social/atproto/commit/8fbdf7885af60020cf218cef2f6d92923b38c864) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Return empty generic record and Atmosphere responses from the local dataplane.
|
|
34
|
+
|
|
35
|
+
- [#5595](https://github.com/bluesky-social/atproto/pull/5595) [`db3e7ad`](https://github.com/bluesky-social/atproto/commit/db3e7adc4bac5fc5e7f8632c8b9d64477d431a4b) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Restrict getFeed passthrough headers to allowlisted feed generators
|
|
36
|
+
|
|
37
|
+
- [#5596](https://github.com/bluesky-social/atproto/pull/5596) [`8fbdf78`](https://github.com/bluesky-social/atproto/commit/8fbdf7885af60020cf218cef2f6d92923b38c864) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Consolidate local Site Standard stubs into the Atmosphere routes.
|
|
38
|
+
|
|
39
|
+
- [#5539](https://github.com/bluesky-social/atproto/pull/5539) [`3312992`](https://github.com/bluesky-social/atproto/commit/3312992fe2cb7ebc009fe4b1f4cc6bc7518b19db) Thanks [@ds-boyce](https://github.com/ds-boyce)! - Pass suggested feed and starter pack recommendation IDs through AppView responses.
|
|
40
|
+
|
|
41
|
+
- [#5539](https://github.com/bluesky-social/atproto/pull/5539) [`3312992`](https://github.com/bluesky-social/atproto/commit/3312992fe2cb7ebc009fe4b1f4cc6bc7518b19db) Thanks [@ds-boyce](https://github.com/ds-boyce)! - Authenticate AppView requests to Iris with a dedicated API key.
|
|
42
|
+
|
|
43
|
+
- [#5595](https://github.com/bluesky-social/atproto/pull/5595) [`db3e7ad`](https://github.com/bluesky-social/atproto/commit/db3e7adc4bac5fc5e7f8632c8b9d64477d431a4b) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Add config support for Bluesky-owned feed generator service DIDs
|
|
44
|
+
- Updated dependencies [[`3312992`](https://github.com/bluesky-social/atproto/commit/3312992fe2cb7ebc009fe4b1f4cc6bc7518b19db)]:
|
|
45
|
+
- @atproto/api@0.23.2
|
|
46
|
+
|
|
3
47
|
## 0.1.1
|
|
4
48
|
|
|
5
49
|
### Patch Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getSuggestions.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/actor/getSuggestions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAyB,MAAM,EAAE,MAAM,sBAAsB,CAAA;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAcxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"getSuggestions.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/actor/getSuggestions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAyB,MAAM,EAAE,MAAM,sBAAsB,CAAA;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAcxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QA8CvD"}
|
|
@@ -12,7 +12,11 @@ export default function (server, ctx) {
|
|
|
12
12
|
handler: async ({ params, auth, req, signal }) => {
|
|
13
13
|
const viewer = auth.credentials.iss;
|
|
14
14
|
const labelers = ctx.reqLabelers(req);
|
|
15
|
-
const hydrateCtx = await ctx.hydrator.createContext({
|
|
15
|
+
const hydrateCtx = await ctx.hydrator.createContext({
|
|
16
|
+
viewer,
|
|
17
|
+
labelers,
|
|
18
|
+
features: ctx.featureGatesClient.scope(ctx.featureGatesClient.parseUserContextFromHandler({ viewer, req })),
|
|
19
|
+
});
|
|
16
20
|
const headers = noUndefinedVals({
|
|
17
21
|
'accept-language': req.headers['accept-language'],
|
|
18
22
|
...getAtprotoPassthroughHeaders(req),
|
|
@@ -40,8 +44,10 @@ export default function (server, ctx) {
|
|
|
40
44
|
const skeleton = async (input) => {
|
|
41
45
|
const { ctx, params } = input;
|
|
42
46
|
const viewer = params.hydrateCtx.viewer;
|
|
43
|
-
|
|
44
|
-
|
|
47
|
+
const useIris = params.hydrateCtx.features.checkGate(params.hydrateCtx.features.Gate.SuggestedUsersIrisEnable);
|
|
48
|
+
const client = useIris ? ctx.irisClient : ctx.suggestionsClient;
|
|
49
|
+
if (viewer && client) {
|
|
50
|
+
const res = await client.xrpc(app.bsky.unspecced.getSuggestionsSkeleton, {
|
|
45
51
|
headers: params.headers,
|
|
46
52
|
signal: params.signal,
|
|
47
53
|
params: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getSuggestions.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/actor/getSuggestions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAC7D,OAAO,EAA+B,WAAW,EAAE,MAAM,cAAc,CAAA;AASvE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAC3D,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAA;AAE1E,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAEvD,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,cAAc,GAAG,cAAc,CACnC,QAAQ,EACR,SAAS,EACT,eAAe,EACf,YAAY,CACb,CAAA;IACD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE;QACxC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,gBAAgB;QACvC,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;YAC/C,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,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"getSuggestions.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/actor/getSuggestions.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined, noUndefinedVals } from '@atproto/common'\nimport { type Client, type DidString, isDidString } from '@atproto/lex'\nimport type { Headers as HeadersMap, Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport type { DataPlaneClient } from '../../../../data-plane/index.js'\nimport type {\n HydrateCtx,\n HydrationState,\n Hydrator,\n} from '../../../../hydration/hydrator.js'\nimport { parseString } from '../../../../hydration/util.js'\nimport { app } from '../../../../lexicons/index.js'\nimport { createPipeline } from '../../../../pipeline.js'\nimport { getAtprotoPassthroughHeaders } from '../../../../util/headers.js'\nimport type { Views } from '../../../../views/index.js'\nimport { fillPage, resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getSuggestions = createPipeline(\n skeleton,\n hydration,\n noBlocksOrMutes,\n presentation,\n )\n server.add(app.bsky.actor.getSuggestions, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ params, auth, req, signal }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n viewer,\n labelers,\n features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({ viewer, req }),\n ),\n })\n const headers = noUndefinedVals({\n 'accept-language': req.headers['accept-language'],\n ...getAtprotoPassthroughHeaders(req),\n })\n const { resHeaders: resultHeaders, ...result } = await fillPage({\n cursor: params.cursor,\n limit: params.limit,\n fetch: ({ cursor, limit }) =>\n getSuggestions(\n { ...params, cursor, limit, hydrateCtx, headers, signal },\n ctx,\n ),\n items: (r) => r.actors,\n })\n const suggestionsResHeaders = noUndefinedVals({\n 'content-language': resultHeaders?.get('content-language'),\n })\n return {\n encoding: 'application/json',\n body: result,\n headers: {\n ...suggestionsResHeaders,\n ...resHeaders({ labelers: hydrateCtx.labelers }),\n },\n }\n },\n })\n}\n\nconst skeleton = async (input: {\n ctx: Context\n params: Params\n}): Promise<Skeleton> => {\n const { ctx, params } = input\n const viewer = params.hydrateCtx.viewer\n const useIris = params.hydrateCtx.features.checkGate(\n params.hydrateCtx.features.Gate.SuggestedUsersIrisEnable,\n )\n const client = useIris ? ctx.irisClient : ctx.suggestionsClient\n\n if (viewer && client) {\n const res = await client.xrpc(app.bsky.unspecced.getSuggestionsSkeleton, {\n headers: params.headers,\n signal: params.signal,\n params: {\n relativeToDid: viewer,\n viewer: viewer ?? undefined,\n limit: params.limit,\n cursor: params.cursor,\n },\n })\n return {\n dids: res.body.actors.map((a) => a.did),\n cursor: res.body.cursor,\n recId: res.body.recId,\n recIdStr: res.body.recIdStr,\n resHeaders: res.headers,\n }\n } else {\n // @NOTE for appview swap moving to rkey-based cursors which are somewhat permissive, should not hard-break pagination\n const suggestions = await ctx.dataplane.getFollowSuggestions({\n actorDid: viewer ?? undefined,\n cursor: params.cursor,\n limit: params.limit,\n })\n // @NOTE filtering to avoid type casting\n let dids = suggestions.dids.filter(isDidString)\n if (viewer !== null) {\n const follows = await ctx.dataplane.getActorFollowsActors({\n actorDid: viewer,\n targetDids: dids,\n })\n dids = dids.filter((did, i) => !follows.uris[i] && did !== viewer)\n }\n return { dids, cursor: parseString(suggestions.cursor) }\n }\n}\n\nconst hydration = async (input: {\n ctx: Context\n params: Params\n skeleton: Skeleton\n}) => {\n const { ctx, params, skeleton } = input\n return ctx.hydrator.hydrateProfilesDetailed(skeleton.dids, params.hydrateCtx)\n}\n\nconst noBlocksOrMutes = (input: {\n ctx: Context\n params: Params\n skeleton: Skeleton\n hydration: HydrationState\n}) => {\n const { ctx, skeleton, hydration } = input\n skeleton.dids = skeleton.dids.filter(\n (did) =>\n !ctx.views.viewerBlockExists(did, hydration) &&\n !ctx.views.viewerMuteExists(did, hydration),\n )\n return skeleton\n}\n\nconst presentation = (input: {\n ctx: Context\n params: Params\n skeleton: Skeleton\n hydration: HydrationState\n}) => {\n const { ctx, skeleton, hydration } = input\n const actors = mapDefined(skeleton.dids, (did) =>\n ctx.views.profileKnownFollowers(did, hydration),\n )\n return {\n actors,\n cursor: skeleton.cursor,\n recId: skeleton.recId,\n recIdStr: skeleton.recIdStr,\n resHeaders: skeleton.resHeaders,\n }\n}\n\ntype Context = {\n suggestionsClient: Client | undefined\n irisClient: Client | undefined\n dataplane: DataPlaneClient\n hydrator: Hydrator\n views: Views\n}\n\ntype Params = app.bsky.actor.getSuggestions.$Params & {\n hydrateCtx: HydrateCtx\n headers: HeadersMap\n signal: AbortSignal\n}\n\ntype Skeleton = {\n dids: DidString[]\n cursor?: string\n recId?: number\n recIdStr?: string\n resHeaders?: Headers\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getFeed.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/feed/getFeed.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,SAAS,EAIf,MAAM,cAAc,CAAA;AAErB,OAAO,EACL,KAAK,OAAO,IAAI,UAAU,EAE1B,KAAK,MAAM,EAKZ,MAAM,sBAAsB,CAAA;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"getFeed.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/feed/getFeed.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,SAAS,EAIf,MAAM,cAAc,CAAA;AAErB,OAAO,EACL,KAAK,OAAO,IAAI,UAAU,EAE1B,KAAK,MAAM,EAKZ,MAAM,sBAAsB,CAAA;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAQxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAA;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAanE,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QA0DvD;AAsHD;;;GAGG;AACH,eAAO,MAAM,cAAc,QACpB,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,cAAc,CAAC,UAC3C;IACN,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE;QACV,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;QAC5B,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC,CAAA;KAC7D,CAAA;CACF,KACA,MAAM,GAAG,SAWX,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAC3B,IAAI,CAAC,YAAY,EAAE,gBAAgB,GAAG,qBAAqB,CAAC,UACzD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,KACvB,MAAM,GAAG,SACgE,CAAA;AAE5E;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,GAAG,gBAAgB,GAAG,iBAAiB,CAAC,EACzE,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,CAAA;CAAE,GAC3C,MAAM,GAAG,SAAS,CAMpB;AA6ID,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,gBAAgB,EAAE,CAAA;IAC7B,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG;IACxC,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA"}
|
|
@@ -3,6 +3,7 @@ import { XrpcInvalidResponseError, XrpcResponseError, xrpcSafe, } from '@atproto
|
|
|
3
3
|
import { AtUri } from '@atproto/syntax';
|
|
4
4
|
import { InvalidRequestError, ServerTimer, UpstreamFailureError, XRPCError, serverTimingHeader, } from '@atproto/xrpc-server';
|
|
5
5
|
import { Code, getServiceEndpoint, isDataplaneError, unpackIdentityServices, } from '../../../../data-plane/index.js';
|
|
6
|
+
import { Gate } from '../../../../feature-gates/gates.js';
|
|
6
7
|
import { app } from '../../../../lexicons/index.js';
|
|
7
8
|
import { createPipeline, } from '../../../../pipeline.js';
|
|
8
9
|
import { getAtprotoPassthroughHeaders } from '../../../../util/headers.js';
|
|
@@ -29,12 +30,12 @@ export default function (server, ctx) {
|
|
|
29
30
|
'user-agent': BSKY_USER_AGENT,
|
|
30
31
|
authorization: req.headers['authorization'],
|
|
31
32
|
'accept-language': req.headers['accept-language'],
|
|
32
|
-
...getAtprotoPassthroughHeaders(req),
|
|
33
33
|
});
|
|
34
|
+
const passthroughHeaders = getAtprotoPassthroughHeaders(req);
|
|
34
35
|
// @NOTE feed cursors should not be affected by appview swap
|
|
35
36
|
// Do not refill filtered pages. Overfetching from algorithmic feeds can
|
|
36
37
|
// advance their state and prevent omitted items from appearing later.
|
|
37
|
-
const result = await getFeed({ ...params, hydrateCtx, headers, signal }, ctx);
|
|
38
|
+
const result = await getFeed({ ...params, hydrateCtx, headers, passthroughHeaders, signal }, ctx);
|
|
38
39
|
const { timerSkele, timerHydr, resHeaders: feedResHeaders, ...body } = result;
|
|
39
40
|
return {
|
|
40
41
|
encoding: 'application/json',
|
|
@@ -106,6 +107,18 @@ const presentation = (inputs) => {
|
|
|
106
107
|
...skeleton.passthrough,
|
|
107
108
|
};
|
|
108
109
|
};
|
|
110
|
+
/**
|
|
111
|
+
* Per-feed rollout gates for the iris cutover, keyed by feed rkey.
|
|
112
|
+
* Allowlisted feeds without a dedicated gate (whats-hot) use Gate.IrisFeed.
|
|
113
|
+
*/
|
|
114
|
+
const IRIS_FEED_RKEY_GATES = {
|
|
115
|
+
'with-friends': Gate.IrisFeedWithFriendsEnable,
|
|
116
|
+
thevids: Gate.IrisFeedThevidsEnable,
|
|
117
|
+
mutuals: Gate.IrisFeedMutualsEnable,
|
|
118
|
+
'bsky-team': Gate.IrisFeedBskyTeamEnable,
|
|
119
|
+
'best-of-follows': Gate.IrisFeedBestOfFollowsEnable,
|
|
120
|
+
followpics: Gate.IrisFeedFollowpicsEnable,
|
|
121
|
+
};
|
|
109
122
|
/**
|
|
110
123
|
* Iris' endpoint, when it should serve this request in place of the feed's
|
|
111
124
|
* registered feed generator (seeemore).
|
|
@@ -118,7 +131,9 @@ export const irisUrlForFeed = (cfg, params) => {
|
|
|
118
131
|
return;
|
|
119
132
|
if (!params.hydrateCtx.viewer)
|
|
120
133
|
return;
|
|
121
|
-
|
|
134
|
+
const rkey = params.feed.split('/').at(-1);
|
|
135
|
+
const gate = (rkey && IRIS_FEED_RKEY_GATES[rkey]) || Gate.IrisFeed;
|
|
136
|
+
if (!params.hydrateCtx.features.checkGate(gate)) {
|
|
122
137
|
return;
|
|
123
138
|
}
|
|
124
139
|
return irisUrl;
|
|
@@ -142,21 +157,25 @@ export function irisUrlForTrendingFeed(cfg, params) {
|
|
|
142
157
|
return irisUrl;
|
|
143
158
|
}
|
|
144
159
|
const resolveSkeletonEndpoint = async (ctx, params) => {
|
|
160
|
+
const { feed } = params;
|
|
145
161
|
const irisUrl = irisUrlForFeed(ctx.cfg, params);
|
|
146
|
-
if (irisUrl)
|
|
147
|
-
return irisUrl;
|
|
162
|
+
if (irisUrl) {
|
|
163
|
+
return { endpoint: irisUrl, feedDid: await getFeedGenDid(ctx, feed) };
|
|
164
|
+
}
|
|
148
165
|
const irisStagingUrl = irisStagingUrlForFeed(ctx.cfg, params);
|
|
149
|
-
if (irisStagingUrl)
|
|
150
|
-
return
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
166
|
+
if (irisStagingUrl) {
|
|
167
|
+
return {
|
|
168
|
+
endpoint: irisStagingUrl,
|
|
169
|
+
feedDid: await getFeedGenDid(ctx, feed),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const feedDid = await getFeedGenDid(ctx, feed);
|
|
154
173
|
if (!feedDid) {
|
|
155
174
|
throw new InvalidRequestError('could not find feed');
|
|
156
175
|
}
|
|
157
176
|
const trendingIrisUrl = irisUrlForTrendingFeed(ctx.cfg, { feed, feedDid });
|
|
158
177
|
if (trendingIrisUrl)
|
|
159
|
-
return trendingIrisUrl;
|
|
178
|
+
return { endpoint: trendingIrisUrl, feedDid };
|
|
160
179
|
let identity;
|
|
161
180
|
try {
|
|
162
181
|
identity = await ctx.dataplane.getIdentityByDid({ did: feedDid });
|
|
@@ -175,11 +194,21 @@ const resolveSkeletonEndpoint = async (ctx, params) => {
|
|
|
175
194
|
if (!fgEndpoint) {
|
|
176
195
|
throw new InvalidRequestError(`invalid feed generator service details in did document: ${feedDid}`);
|
|
177
196
|
}
|
|
178
|
-
return fgEndpoint;
|
|
197
|
+
return { endpoint: fgEndpoint, feedDid };
|
|
179
198
|
};
|
|
199
|
+
async function getFeedGenDid(ctx, feed) {
|
|
200
|
+
const found = await ctx.hydrator.feed.getFeedGens([feed], true);
|
|
201
|
+
return found.get(feed)?.record.did;
|
|
202
|
+
}
|
|
180
203
|
const skeletonFromFeedGen = async (ctx, params) => {
|
|
181
|
-
const { headers } = params;
|
|
182
|
-
const endpoint = await resolveSkeletonEndpoint(ctx, params);
|
|
204
|
+
const { headers, passthroughHeaders } = params;
|
|
205
|
+
const { endpoint, feedDid } = await resolveSkeletonEndpoint(ctx, params);
|
|
206
|
+
const requestHeaders = noUndefinedVals({
|
|
207
|
+
...headers,
|
|
208
|
+
...(feedDid && ctx.cfg.bskyFeedgenDids.has(feedDid)
|
|
209
|
+
? passthroughHeaders
|
|
210
|
+
: {}),
|
|
211
|
+
});
|
|
183
212
|
// @TODO currently passthrough auth headers from pds
|
|
184
213
|
const result = await xrpcSafe(endpoint, app.bsky.feed.getFeedSkeleton, {
|
|
185
214
|
strictResponseProcessing: false,
|
|
@@ -187,7 +216,7 @@ const skeletonFromFeedGen = async (ctx, params) => {
|
|
|
187
216
|
params.signal,
|
|
188
217
|
AbortSignal.timeout(ctx.cfg.feedGenSkeletonTimeout),
|
|
189
218
|
]),
|
|
190
|
-
headers,
|
|
219
|
+
headers: requestHeaders,
|
|
191
220
|
params: {
|
|
192
221
|
feed: params.feed,
|
|
193
222
|
// The feedgen is not guaranteed to honor the limit, but we try it.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getFeed.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/feed/getFeed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAC7D,OAAO,EAEL,wBAAwB,EACxB,iBAAiB,EACjB,QAAQ,GACT,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AACvC,OAAO,EAEL,mBAAmB,EAEnB,WAAW,EACX,oBAAoB,EACpB,SAAS,EACT,kBAAkB,GACnB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EACL,IAAI,EACJ,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,iCAAiC,CAAA;AAGxC,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAKL,cAAc,GACf,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAA;AAC1E,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE9D,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,OAAO,GAAG,cAAc,CAC5B,QAAQ,EACR,SAAS,EACT,eAAe,EACf,YAAY,CACb,CAAA;IACD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;QAChC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,6BAA6B,CAAC;YACnD,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;gBACnB,OAAO,CACL,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI;oBAC7C,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CACtC,CAAA;YACH,CAAC;YACD,YAAY,EAAE,IAAI;SACnB,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;YAC/C,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;gBAClD,QAAQ;gBACR,MAAM;gBACN,QAAQ,EAAE,GAAG,CAAC,kBAAkB,CAAC,KAAK,CACpC,GAAG,CAAC,kBAAkB,CAAC,2BAA2B,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CACpE;aACF,CAAC,CAAA;YACF,MAAM,OAAO,GAAG,eAAe,CAAC;gBAC9B,YAAY,EAAE,eAAe;gBAC7B,aAAa,EAAE,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC;gBAC3C,iBAAiB,EAAE,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC;gBACjD,GAAG,4BAA4B,CAAC,GAAG,CAAC;aACrC,CAAC,CAAA;YACF,4DAA4D;YAC5D,wEAAwE;YACxE,sEAAsE;YACtE,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,EAC1C,GAAG,CACJ,CAAA;YACD,MAAM,EACJ,UAAU,EACV,SAAS,EACT,UAAU,EAAE,cAAc,EAC1B,GAAG,IAAI,EACR,GAAG,MAAM,CAAA;YAEV,OAAO;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI;gBACJ,OAAO,EAAE;oBACP,GAAG,cAAc;oBACjB,GAAG,UAAU,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC;oBAChD,eAAe,EAAE,kBAAkB,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;iBAC7D;aACF,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,QAAQ,GAAG,KAAK,EACpB,MAAwC,EACrB,EAAE;IACrB,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;IAC9B,MAAM,UAAU,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAA;IACnD,MAAM,EACJ,SAAS,EAAE,SAAS,EACpB,KAAK,EACL,MAAM,EACN,UAAU,EACV,GAAG,WAAW,EACf,GAAG,MAAM,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;IAE1C,OAAO;QACL,MAAM;QACN,KAAK,EAAE,SAAS;QAChB,KAAK;QACL,UAAU,EAAE,UAAU,CAAC,IAAI,EAAE;QAC7B,SAAS,EAAE,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE;QAC1C,UAAU;QACV,WAAW;KACZ,CAAA;AACH,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,KAAK,EACrB,MAAmD,EACnD,EAAE;IACF,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAA;IACxC,MAAM,SAAS,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,CAAA;IACjD,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CACnD,QAAQ,CAAC,KAAK,EACd,MAAM,CAAC,UAAU,EACjB;QACE,WAAW,EACT,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM;YAC1B,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAClC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,qBAAqB,CACtD;KACJ,CACF,CAAA;IACD,QAAQ,CAAC,SAAS,GAAG,SAAS,CAAC,IAAI,EAAE,CAAA;IACrC,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA;AAED,MAAM,eAAe,GAAG,CAAC,MAA+C,EAAE,EAAE;IAC1E,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,CAAA;IAC3C,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAC9C,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,sBAAsB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QAC7D,OAAO,CACL,CAAC,GAAG,CAAC,aAAa;YAClB,CAAC,GAAG,CAAC,WAAW;YAChB,CAAC,GAAG,CAAC,oBAAoB;YACzB,CAAC,GAAG,CAAC,iBAAiB;YACtB,CAAC,GAAG,CAAC,eAAe;YACpB,CAAC,GAAG,CAAC,qBAAqB;YAC1B,CAAC,GAAG,CAAC,qBAAqB,CAC3B,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,OAAO,QAAQ,CAAA;AACjB,CAAC,CAAA;AAED,MAAM,YAAY,GAAG,CACnB,MAAsD,EACtD,EAAE;IACF,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,CAAA;IAC3C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE;QAC/C,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;QACpD,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,OAAO;YACL,GAAG,IAAI;YACP,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,CAAA;IACH,CAAC,CAAC,CAAA;IACF,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;QAC1D,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,GAAG,QAAQ,CAAC,WAAW;KACxB,CAAA;AACH,CAAC,CAAA;AAoBD;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,GAAmD,EACnD,MAMC,EACmB,EAAE;IACtB,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAA;IACvB,IAAI,CAAC,OAAO;QAAE,OAAM;IACpB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;QAAE,OAAM;IAC/C,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM;QAAE,OAAM;IACrC,IACE,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CACnC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CACzC,EACD,CAAC;QACD,OAAM;IACR,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,GAAiE,EACjE,MAAwB,EACJ,EAAE,CACtB,GAAG,CAAC,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAA;AAE5E;;GAEG;AACH,MAAM,UAAU,sBAAsB,CACpC,GAAyE,EACzE,MAA4C;IAE5C,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,GAAG,GAAG,CAAA;IACxD,IAAI,CAAC,OAAO,IAAI,CAAC,cAAc,IAAI,CAAC,eAAe;QAAE,OAAM;IAC3D,IAAI,MAAM,CAAC,OAAO,KAAK,cAAc;QAAE,OAAM;IAC7C,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,eAAe;QAAE,OAAM;IAC3D,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,uBAAuB,GAAG,KAAK,EACnC,GAAY,EACZ,MAAc,EACG,EAAE;IACnB,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;IAC/C,IAAI,OAAO;QAAE,OAAO,OAAO,CAAA;IAE3B,MAAM,cAAc,GAAG,qBAAqB,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;IAC7D,IAAI,cAAc;QAAE,OAAO,cAAc,CAAA;IAEzC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,CAAA;IACvB,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAA;IAC/D,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,GAAG,CAAA;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,mBAAmB,CAAC,qBAAqB,CAAC,CAAA;IACtD,CAAC;IAED,MAAM,eAAe,GAAG,sBAAsB,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IAC1E,IAAI,eAAe;QAAE,OAAO,eAAe,CAAA;IAE3C,IAAI,QAAkC,CAAA;IACtC,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAA;IACnE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,mBAAmB,CAAC,+BAA+B,OAAO,EAAE,CAAC,CAAA;QACzE,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;IAED,MAAM,QAAQ,GAAG,sBAAsB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IAC1D,MAAM,UAAU,GAAG,kBAAkB,CAAC,QAAQ,EAAE;QAC9C,EAAE,EAAE,SAAS;QACb,IAAI,EAAE,mBAAmB;KAC1B,CAAC,CAAA;IACF,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,mBAAmB,CAC3B,2DAA2D,OAAO,EAAE,CACrE,CAAA;IACH,CAAC;IAED,OAAO,UAAU,CAAA;AACnB,CAAC,CAAA;AAED,MAAM,mBAAmB,GAAG,KAAK,EAC/B,GAAY,EACZ,MAAc,EACS,EAAE;IACzB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAA;IAC1B,MAAM,QAAQ,GAAG,MAAM,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;IAE3D,oDAAoD;IACpD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;QACrE,wBAAwB,EAAE,KAAK;QAC/B,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC;YACtB,MAAM,CAAC,MAAM;YACb,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,sBAAsB,CAAC;SACpD,CAAC;QACF,OAAO;QACP,MAAM,EAAE;YACN,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,mEAAmE;YACnE,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB;KACF,CAAC,CAAA;IAEF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAA;QAE3B,yEAAyE;QACzE,cAAc;QACd,IAAI,KAAK,YAAY,iBAAiB,EAAE,CAAC;YACvC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,iBAAiB,EAAE,CAAA;YAClD,MAAM,IAAI,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;QAClE,CAAC;QAED,yCAAyC;QACzC,IAAI,KAAK,YAAY,wBAAwB,EAAE,CAAC;YAC9C,MAAM,IAAI,oBAAoB,CAC5B,mCAAmC,EACnC,qBAAqB,EACrB,EAAE,KAAK,EAAE,CACV,CAAA;QACH,CAAC;QAED,6BAA6B;QAC7B,MAAM,IAAI,oBAAoB,CAAC,kBAAkB,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;IAC1E,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,GAAG,MAAM,CAAC,IAAI,CAAA;IACzD,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAChE,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE;QACxB,MAAM,EACJ,IAAI,CAAC,MAAM,IAAI,IAAI;YACnB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;YAC5D,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;YAC7B,CAAC,CAAC,SAAS;QACf,YAAY,EACV,IAAI,CAAC,MAAM,IAAI,IAAI;YACnB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;YACzD,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,SAAS;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;KAC9B,CAAC,CAAC,CAAA;IAEH,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;IAE1D,OAAO;QACL,GAAG,KAAK;QACR,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS;QACzE,SAAS;QACT,6EAA6E;QAC7E,sEAAsE;QACtE,MAAM,EACJ,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;KAC1E,CAAA;AACH,CAAC,CAAA","sourcesContent":["import { mapDefined, noUndefinedVals } from '@atproto/common'\nimport {\n type DidString,\n XrpcInvalidResponseError,\n XrpcResponseError,\n xrpcSafe,\n} from '@atproto/lex'\nimport { AtUri } from '@atproto/syntax'\nimport {\n type Headers as HeadersMap,\n InvalidRequestError,\n type Server,\n ServerTimer,\n UpstreamFailureError,\n XRPCError,\n serverTimingHeader,\n} from '@atproto/xrpc-server'\nimport type { ServerConfig } from '../../../../config.js'\nimport type { AppContext } from '../../../../context.js'\nimport {\n Code,\n getServiceEndpoint,\n isDataplaneError,\n unpackIdentityServices,\n} from '../../../../data-plane/index.js'\nimport type { FeedItem } from '../../../../hydration/feed.js'\nimport type { HydrateCtx } from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type RulesFnInput,\n type SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline.js'\nimport type { GetIdentityByDidResponse } from '../../../../proto/bsky_pb.js'\nimport { getAtprotoPassthroughHeaders } from '../../../../util/headers.js'\nimport { BSKY_USER_AGENT, resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getFeed = createPipeline(\n skeleton,\n hydration,\n noBlocksOrMutes,\n presentation,\n )\n server.add(app.bsky.feed.getFeed, {\n auth: ctx.authVerifier.standardOptionalParameterized({\n lxmCheck: (method) => {\n return (\n method === app.bsky.feed.getFeedSkeleton.$lxm ||\n method === app.bsky.feed.getFeed.$lxm\n )\n },\n skipAudCheck: true,\n }),\n handler: async ({ params, auth, req, signal }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n labelers,\n viewer,\n features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({ viewer, req }),\n ),\n })\n const headers = noUndefinedVals({\n 'user-agent': BSKY_USER_AGENT,\n authorization: req.headers['authorization'],\n 'accept-language': req.headers['accept-language'],\n ...getAtprotoPassthroughHeaders(req),\n })\n // @NOTE feed cursors should not be affected by appview swap\n // Do not refill filtered pages. Overfetching from algorithmic feeds can\n // advance their state and prevent omitted items from appearing later.\n const result = await getFeed(\n { ...params, hydrateCtx, headers, signal },\n ctx,\n )\n const {\n timerSkele,\n timerHydr,\n resHeaders: feedResHeaders,\n ...body\n } = result\n\n return {\n encoding: 'application/json',\n body,\n headers: {\n ...feedResHeaders,\n ...resHeaders({ labelers: hydrateCtx.labelers }),\n 'server-timing': serverTimingHeader([timerSkele, timerHydr]),\n },\n }\n },\n })\n}\n\nconst skeleton = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n const { ctx, params } = inputs\n const timerSkele = new ServerTimer('skele').start()\n const {\n feedItems: algoItems,\n reqId,\n cursor,\n resHeaders,\n ...passthrough\n } = await skeletonFromFeedGen(ctx, params)\n\n return {\n cursor,\n items: algoItems,\n reqId,\n timerSkele: timerSkele.stop(),\n timerHydr: new ServerTimer('hydr').start(),\n resHeaders,\n passthrough,\n }\n}\n\nconst hydration = async (\n inputs: HydrationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, params, skeleton } = inputs\n const timerHydr = new ServerTimer('hydr').start()\n const hydration = await ctx.hydrator.hydrateFeedItems(\n skeleton.items,\n params.hydrateCtx,\n {\n knownLikers:\n !!params.hydrateCtx.viewer &&\n params.hydrateCtx.features.checkGate(\n params.hydrateCtx.features.Gate.KnownLikersFeedEnable,\n ),\n },\n )\n skeleton.timerHydr = timerHydr.stop()\n return hydration\n}\n\nconst noBlocksOrMutes = (inputs: RulesFnInput<Context, Params, Skeleton>) => {\n const { ctx, skeleton, hydration } = inputs\n skeleton.items = skeleton.items.filter((item) => {\n const bam = ctx.views.feedItemBlocksAndMutes(item, hydration)\n return (\n !bam.authorBlocked &&\n !bam.authorMuted &&\n !bam.authorQuotepostMuted &&\n !bam.originatorBlocked &&\n !bam.originatorMuted &&\n !bam.originatorRepostMuted &&\n !bam.ancestorAuthorBlocked\n )\n })\n\n return skeleton\n}\n\nconst presentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, skeleton, hydration } = inputs\n const feed = mapDefined(skeleton.items, (item) => {\n const post = ctx.views.feedViewPost(item, hydration)\n if (!post) return\n return {\n ...post,\n feedContext: item.feedContext,\n }\n })\n return {\n feed: feed.map((fi) => ({ ...fi, reqId: skeleton.reqId })),\n cursor: skeleton.cursor,\n timerSkele: skeleton.timerSkele,\n timerHydr: skeleton.timerHydr,\n resHeaders: skeleton.resHeaders,\n ...skeleton.passthrough,\n }\n}\n\ntype Context = AppContext\n\ntype Params = app.bsky.feed.getFeed.$Params & {\n hydrateCtx: HydrateCtx\n headers: HeadersMap\n signal: AbortSignal\n}\n\ntype Skeleton = {\n items: AlgoResponseItem[]\n reqId?: string\n passthrough: Record<string, unknown> // pass through additional items in feedgen response\n resHeaders?: HeadersMap\n cursor?: string\n timerSkele: ServerTimer\n timerHydr: ServerTimer\n}\n\n/**\n * Iris' endpoint, when it should serve this request in place of the feed's\n * registered feed generator (seeemore).\n */\nexport const irisUrlForFeed = (\n cfg: Pick<ServerConfig, 'irisUrl' | 'irisFeedUris'>,\n params: {\n feed: string\n hydrateCtx: {\n viewer: HydrateCtx['viewer']\n features: Pick<HydrateCtx['features'], 'Gate' | 'checkGate'>\n }\n },\n): string | undefined => {\n const { irisUrl } = cfg\n if (!irisUrl) return\n if (!cfg.irisFeedUris?.has(params.feed)) return\n if (!params.hydrateCtx.viewer) return\n if (\n !params.hydrateCtx.features.checkGate(\n params.hydrateCtx.features.Gate.IrisFeed,\n )\n ) {\n return\n }\n return irisUrl\n}\n\n/**\n * Iris staging's endpoint, when it should serve this request in place of the\n * feed's registered feed generator.\n */\nexport const irisStagingUrlForFeed = (\n cfg: Pick<ServerConfig, 'irisStagingUrl' | 'irisStagingFeedUris'>,\n params: { feed: string },\n): string | undefined =>\n cfg.irisStagingFeedUris?.has(params.feed) ? cfg.irisStagingUrl : undefined\n\n/**\n * Iris' local endpoint for configured trending feeds registered to Iris.\n */\nexport function irisUrlForTrendingFeed(\n cfg: Pick<ServerConfig, 'irisUrl' | 'irisServiceDid' | 'trendingFeedDid'>,\n params: { feed: string; feedDid: DidString },\n): string | undefined {\n const { irisUrl, irisServiceDid, trendingFeedDid } = cfg\n if (!irisUrl || !irisServiceDid || !trendingFeedDid) return\n if (params.feedDid !== irisServiceDid) return\n if (new AtUri(params.feed).host !== trendingFeedDid) return\n return irisUrl\n}\n\nconst resolveSkeletonEndpoint = async (\n ctx: Context,\n params: Params,\n): Promise<string> => {\n const irisUrl = irisUrlForFeed(ctx.cfg, params)\n if (irisUrl) return irisUrl\n\n const irisStagingUrl = irisStagingUrlForFeed(ctx.cfg, params)\n if (irisStagingUrl) return irisStagingUrl\n\n const { feed } = params\n const found = await ctx.hydrator.feed.getFeedGens([feed], true)\n const feedDid = found.get(feed)?.record.did\n if (!feedDid) {\n throw new InvalidRequestError('could not find feed')\n }\n\n const trendingIrisUrl = irisUrlForTrendingFeed(ctx.cfg, { feed, feedDid })\n if (trendingIrisUrl) return trendingIrisUrl\n\n let identity: GetIdentityByDidResponse\n try {\n identity = await ctx.dataplane.getIdentityByDid({ did: feedDid })\n } catch (err) {\n if (isDataplaneError(err, Code.NotFound)) {\n throw new InvalidRequestError(`could not resolve identity: ${feedDid}`)\n }\n throw err\n }\n\n const services = unpackIdentityServices(identity.services)\n const fgEndpoint = getServiceEndpoint(services, {\n id: 'bsky_fg',\n type: 'BskyFeedGenerator',\n })\n if (!fgEndpoint) {\n throw new InvalidRequestError(\n `invalid feed generator service details in did document: ${feedDid}`,\n )\n }\n\n return fgEndpoint\n}\n\nconst skeletonFromFeedGen = async (\n ctx: Context,\n params: Params,\n): Promise<AlgoResponse> => {\n const { headers } = params\n const endpoint = await resolveSkeletonEndpoint(ctx, params)\n\n // @TODO currently passthrough auth headers from pds\n const result = await xrpcSafe(endpoint, app.bsky.feed.getFeedSkeleton, {\n strictResponseProcessing: false,\n signal: AbortSignal.any([\n params.signal,\n AbortSignal.timeout(ctx.cfg.feedGenSkeletonTimeout),\n ]),\n headers,\n params: {\n feed: params.feed,\n // The feedgen is not guaranteed to honor the limit, but we try it.\n limit: params.limit,\n cursor: params.cursor,\n },\n })\n\n if (!result.success) {\n const cause = result.reason\n\n // Pass through structurally valid XRPC error response (4xx/5xx), such as\n // auth errors\n if (cause instanceof XrpcResponseError) {\n const { status, body } = cause.toDownstreamError()\n throw new XRPCError(status, body.message, body.error, { cause })\n }\n\n // The response does not match the schema\n if (cause instanceof XrpcInvalidResponseError) {\n throw new UpstreamFailureError(\n 'feed provided an invalid response',\n 'InvalidFeedResponse',\n { cause },\n )\n }\n\n // Typically a network error.\n throw new UpstreamFailureError('feed unavailable', undefined, { cause })\n }\n\n const { feed: feedSkele, cursor, ...skele } = result.body\n const feedItems = feedSkele.slice(0, params.limit).map((item) => ({\n post: { uri: item.post },\n repost:\n item.reason != null &&\n app.bsky.feed.defs.skeletonReasonRepost.$isTypeOf(item.reason)\n ? { uri: item.reason.repost }\n : undefined,\n authorPinned:\n item.reason != null &&\n app.bsky.feed.defs.skeletonReasonPin.$isTypeOf(item.reason)\n ? true\n : undefined,\n feedContext: item.feedContext,\n }))\n\n const contentLang = result.headers.get('content-language')\n\n return {\n ...skele,\n resHeaders: contentLang ? { 'content-language': contentLang } : undefined,\n feedItems,\n // An empty feed-generator page ends pagination even if it includes a cursor.\n // Also prevent loops if the custom feed echoes the input cursor back.\n cursor:\n feedSkele.length === 0 || cursor === params.cursor ? undefined : cursor,\n }\n}\n\nexport type AlgoResponse = {\n feedItems: AlgoResponseItem[]\n resHeaders?: HeadersMap\n cursor?: string\n reqId?: string\n}\n\nexport type AlgoResponseItem = FeedItem & {\n feedContext?: string\n}\n"]}
|
|
1
|
+
{"version":3,"file":"getFeed.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/feed/getFeed.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined, noUndefinedVals } from '@atproto/common'\nimport {\n type DidString,\n XrpcInvalidResponseError,\n XrpcResponseError,\n xrpcSafe,\n} from '@atproto/lex'\nimport { AtUri } from '@atproto/syntax'\nimport {\n type Headers as HeadersMap,\n InvalidRequestError,\n type Server,\n ServerTimer,\n UpstreamFailureError,\n XRPCError,\n serverTimingHeader,\n} from '@atproto/xrpc-server'\nimport type { ServerConfig } from '../../../../config.js'\nimport type { AppContext } from '../../../../context.js'\nimport {\n Code,\n getServiceEndpoint,\n isDataplaneError,\n unpackIdentityServices,\n} from '../../../../data-plane/index.js'\nimport { Gate } from '../../../../feature-gates/gates.js'\nimport type { FeedItem } from '../../../../hydration/feed.js'\nimport type { HydrateCtx } from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type RulesFnInput,\n type SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline.js'\nimport type { GetIdentityByDidResponse } from '../../../../proto/bsky_pb.js'\nimport { getAtprotoPassthroughHeaders } from '../../../../util/headers.js'\nimport { BSKY_USER_AGENT, resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getFeed = createPipeline(\n skeleton,\n hydration,\n noBlocksOrMutes,\n presentation,\n )\n server.add(app.bsky.feed.getFeed, {\n auth: ctx.authVerifier.standardOptionalParameterized({\n lxmCheck: (method) => {\n return (\n method === app.bsky.feed.getFeedSkeleton.$lxm ||\n method === app.bsky.feed.getFeed.$lxm\n )\n },\n skipAudCheck: true,\n }),\n handler: async ({ params, auth, req, signal }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n labelers,\n viewer,\n features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({ viewer, req }),\n ),\n })\n const headers = noUndefinedVals({\n 'user-agent': BSKY_USER_AGENT,\n authorization: req.headers['authorization'],\n 'accept-language': req.headers['accept-language'],\n })\n const passthroughHeaders = getAtprotoPassthroughHeaders(req)\n // @NOTE feed cursors should not be affected by appview swap\n // Do not refill filtered pages. Overfetching from algorithmic feeds can\n // advance their state and prevent omitted items from appearing later.\n const result = await getFeed(\n { ...params, hydrateCtx, headers, passthroughHeaders, signal },\n ctx,\n )\n const {\n timerSkele,\n timerHydr,\n resHeaders: feedResHeaders,\n ...body\n } = result\n\n return {\n encoding: 'application/json',\n body,\n headers: {\n ...feedResHeaders,\n ...resHeaders({ labelers: hydrateCtx.labelers }),\n 'server-timing': serverTimingHeader([timerSkele, timerHydr]),\n },\n }\n },\n })\n}\n\nconst skeleton = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n const { ctx, params } = inputs\n const timerSkele = new ServerTimer('skele').start()\n const {\n feedItems: algoItems,\n reqId,\n cursor,\n resHeaders,\n ...passthrough\n } = await skeletonFromFeedGen(ctx, params)\n\n return {\n cursor,\n items: algoItems,\n reqId,\n timerSkele: timerSkele.stop(),\n timerHydr: new ServerTimer('hydr').start(),\n resHeaders,\n passthrough,\n }\n}\n\nconst hydration = async (\n inputs: HydrationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, params, skeleton } = inputs\n const timerHydr = new ServerTimer('hydr').start()\n const hydration = await ctx.hydrator.hydrateFeedItems(\n skeleton.items,\n params.hydrateCtx,\n {\n knownLikers:\n !!params.hydrateCtx.viewer &&\n params.hydrateCtx.features.checkGate(\n params.hydrateCtx.features.Gate.KnownLikersFeedEnable,\n ),\n },\n )\n skeleton.timerHydr = timerHydr.stop()\n return hydration\n}\n\nconst noBlocksOrMutes = (inputs: RulesFnInput<Context, Params, Skeleton>) => {\n const { ctx, skeleton, hydration } = inputs\n skeleton.items = skeleton.items.filter((item) => {\n const bam = ctx.views.feedItemBlocksAndMutes(item, hydration)\n return (\n !bam.authorBlocked &&\n !bam.authorMuted &&\n !bam.authorQuotepostMuted &&\n !bam.originatorBlocked &&\n !bam.originatorMuted &&\n !bam.originatorRepostMuted &&\n !bam.ancestorAuthorBlocked\n )\n })\n\n return skeleton\n}\n\nconst presentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, skeleton, hydration } = inputs\n const feed = mapDefined(skeleton.items, (item) => {\n const post = ctx.views.feedViewPost(item, hydration)\n if (!post) return\n return {\n ...post,\n feedContext: item.feedContext,\n }\n })\n return {\n feed: feed.map((fi) => ({ ...fi, reqId: skeleton.reqId })),\n cursor: skeleton.cursor,\n timerSkele: skeleton.timerSkele,\n timerHydr: skeleton.timerHydr,\n resHeaders: skeleton.resHeaders,\n ...skeleton.passthrough,\n }\n}\n\ntype Context = AppContext\n\ntype Params = app.bsky.feed.getFeed.$Params & {\n hydrateCtx: HydrateCtx\n headers: HeadersMap\n passthroughHeaders: HeadersMap\n signal: AbortSignal\n}\n\ntype Skeleton = {\n items: AlgoResponseItem[]\n reqId?: string\n passthrough: Record<string, unknown> // pass through additional items in feedgen response\n resHeaders?: HeadersMap\n cursor?: string\n timerSkele: ServerTimer\n timerHydr: ServerTimer\n}\n\n/**\n * Per-feed rollout gates for the iris cutover, keyed by feed rkey.\n * Allowlisted feeds without a dedicated gate (whats-hot) use Gate.IrisFeed.\n */\nconst IRIS_FEED_RKEY_GATES: Record<string, Gate> = {\n 'with-friends': Gate.IrisFeedWithFriendsEnable,\n thevids: Gate.IrisFeedThevidsEnable,\n mutuals: Gate.IrisFeedMutualsEnable,\n 'bsky-team': Gate.IrisFeedBskyTeamEnable,\n 'best-of-follows': Gate.IrisFeedBestOfFollowsEnable,\n followpics: Gate.IrisFeedFollowpicsEnable,\n}\n\n/**\n * Iris' endpoint, when it should serve this request in place of the feed's\n * registered feed generator (seeemore).\n */\nexport const irisUrlForFeed = (\n cfg: Pick<ServerConfig, 'irisUrl' | 'irisFeedUris'>,\n params: {\n feed: string\n hydrateCtx: {\n viewer: HydrateCtx['viewer']\n features: Pick<HydrateCtx['features'], 'Gate' | 'checkGate'>\n }\n },\n): string | undefined => {\n const { irisUrl } = cfg\n if (!irisUrl) return\n if (!cfg.irisFeedUris?.has(params.feed)) return\n if (!params.hydrateCtx.viewer) return\n const rkey = params.feed.split('/').at(-1)\n const gate = (rkey && IRIS_FEED_RKEY_GATES[rkey]) || Gate.IrisFeed\n if (!params.hydrateCtx.features.checkGate(gate)) {\n return\n }\n return irisUrl\n}\n\n/**\n * Iris staging's endpoint, when it should serve this request in place of the\n * feed's registered feed generator.\n */\nexport const irisStagingUrlForFeed = (\n cfg: Pick<ServerConfig, 'irisStagingUrl' | 'irisStagingFeedUris'>,\n params: { feed: string },\n): string | undefined =>\n cfg.irisStagingFeedUris?.has(params.feed) ? cfg.irisStagingUrl : undefined\n\n/**\n * Iris' local endpoint for configured trending feeds registered to Iris.\n */\nexport function irisUrlForTrendingFeed(\n cfg: Pick<ServerConfig, 'irisUrl' | 'irisServiceDid' | 'trendingFeedDid'>,\n params: { feed: string; feedDid: DidString },\n): string | undefined {\n const { irisUrl, irisServiceDid, trendingFeedDid } = cfg\n if (!irisUrl || !irisServiceDid || !trendingFeedDid) return\n if (params.feedDid !== irisServiceDid) return\n if (new AtUri(params.feed).host !== trendingFeedDid) return\n return irisUrl\n}\n\nconst resolveSkeletonEndpoint = async (\n ctx: Context,\n params: Params,\n): Promise<{ endpoint: string; feedDid?: DidString }> => {\n const { feed } = params\n const irisUrl = irisUrlForFeed(ctx.cfg, params)\n if (irisUrl) {\n return { endpoint: irisUrl, feedDid: await getFeedGenDid(ctx, feed) }\n }\n\n const irisStagingUrl = irisStagingUrlForFeed(ctx.cfg, params)\n if (irisStagingUrl) {\n return {\n endpoint: irisStagingUrl,\n feedDid: await getFeedGenDid(ctx, feed),\n }\n }\n\n const feedDid = await getFeedGenDid(ctx, feed)\n if (!feedDid) {\n throw new InvalidRequestError('could not find feed')\n }\n\n const trendingIrisUrl = irisUrlForTrendingFeed(ctx.cfg, { feed, feedDid })\n if (trendingIrisUrl) return { endpoint: trendingIrisUrl, feedDid }\n\n let identity: GetIdentityByDidResponse\n try {\n identity = await ctx.dataplane.getIdentityByDid({ did: feedDid })\n } catch (err) {\n if (isDataplaneError(err, Code.NotFound)) {\n throw new InvalidRequestError(`could not resolve identity: ${feedDid}`)\n }\n throw err\n }\n\n const services = unpackIdentityServices(identity.services)\n const fgEndpoint = getServiceEndpoint(services, {\n id: 'bsky_fg',\n type: 'BskyFeedGenerator',\n })\n if (!fgEndpoint) {\n throw new InvalidRequestError(\n `invalid feed generator service details in did document: ${feedDid}`,\n )\n }\n\n return { endpoint: fgEndpoint, feedDid }\n}\n\nasync function getFeedGenDid(\n ctx: Context,\n feed: Params['feed'],\n): Promise<DidString | undefined> {\n const found = await ctx.hydrator.feed.getFeedGens([feed], true)\n return found.get(feed)?.record.did\n}\n\nconst skeletonFromFeedGen = async (\n ctx: Context,\n params: Params,\n): Promise<AlgoResponse> => {\n const { headers, passthroughHeaders } = params\n const { endpoint, feedDid } = await resolveSkeletonEndpoint(ctx, params)\n const requestHeaders = noUndefinedVals({\n ...headers,\n ...(feedDid && ctx.cfg.bskyFeedgenDids.has(feedDid)\n ? passthroughHeaders\n : {}),\n })\n\n // @TODO currently passthrough auth headers from pds\n const result = await xrpcSafe(endpoint, app.bsky.feed.getFeedSkeleton, {\n strictResponseProcessing: false,\n signal: AbortSignal.any([\n params.signal,\n AbortSignal.timeout(ctx.cfg.feedGenSkeletonTimeout),\n ]),\n headers: requestHeaders,\n params: {\n feed: params.feed,\n // The feedgen is not guaranteed to honor the limit, but we try it.\n limit: params.limit,\n cursor: params.cursor,\n },\n })\n\n if (!result.success) {\n const cause = result.reason\n\n // Pass through structurally valid XRPC error response (4xx/5xx), such as\n // auth errors\n if (cause instanceof XrpcResponseError) {\n const { status, body } = cause.toDownstreamError()\n throw new XRPCError(status, body.message, body.error, { cause })\n }\n\n // The response does not match the schema\n if (cause instanceof XrpcInvalidResponseError) {\n throw new UpstreamFailureError(\n 'feed provided an invalid response',\n 'InvalidFeedResponse',\n { cause },\n )\n }\n\n // Typically a network error.\n throw new UpstreamFailureError('feed unavailable', undefined, { cause })\n }\n\n const { feed: feedSkele, cursor, ...skele } = result.body\n const feedItems = feedSkele.slice(0, params.limit).map((item) => ({\n post: { uri: item.post },\n repost:\n item.reason != null &&\n app.bsky.feed.defs.skeletonReasonRepost.$isTypeOf(item.reason)\n ? { uri: item.reason.repost }\n : undefined,\n authorPinned:\n item.reason != null &&\n app.bsky.feed.defs.skeletonReasonPin.$isTypeOf(item.reason)\n ? true\n : undefined,\n feedContext: item.feedContext,\n }))\n\n const contentLang = result.headers.get('content-language')\n\n return {\n ...skele,\n resHeaders: contentLang ? { 'content-language': contentLang } : undefined,\n feedItems,\n // An empty feed-generator page ends pagination even if it includes a cursor.\n // Also prevent loops if the custom feed echoes the input cursor back.\n cursor:\n feedSkele.length === 0 || cursor === params.cursor ? undefined : cursor,\n }\n}\n\nexport type AlgoResponse = {\n feedItems: AlgoResponseItem[]\n resHeaders?: HeadersMap\n cursor?: string\n reqId?: string\n}\n\nexport type AlgoResponseItem = FeedItem & {\n feedContext?: string\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getSuggestedFollowsByActor.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getSuggestedFollowsByActor.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,MAAM,EACZ,MAAM,sBAAsB,CAAA;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAcxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"getSuggestedFollowsByActor.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getSuggestedFollowsByActor.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,MAAM,EACZ,MAAM,sBAAsB,CAAA;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAcxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAwDvD"}
|
|
@@ -19,7 +19,9 @@ export default function (server, ctx) {
|
|
|
19
19
|
req,
|
|
20
20
|
})),
|
|
21
21
|
});
|
|
22
|
-
|
|
22
|
+
const useIris = hydrateCtx.features.checkGate(hydrateCtx.features.Gate.SuggestedUsersIrisEnable);
|
|
23
|
+
const client = useIris ? ctx.irisClient : ctx.suggestionsClient;
|
|
24
|
+
if (!client) {
|
|
23
25
|
return {
|
|
24
26
|
encoding: 'application/json',
|
|
25
27
|
body: { suggestions: [] },
|
|
@@ -44,15 +46,17 @@ export default function (server, ctx) {
|
|
|
44
46
|
}
|
|
45
47
|
const skeleton = async (input) => {
|
|
46
48
|
const { params, ctx } = input;
|
|
49
|
+
const useIris = params.hydrateCtx.features.checkGate(params.hydrateCtx.features.Gate.SuggestedUsersIrisEnable);
|
|
50
|
+
const client = useIris ? ctx.irisClient : ctx.suggestionsClient;
|
|
47
51
|
// handled above already, this branch should not be reached
|
|
48
|
-
if (!
|
|
52
|
+
if (!client) {
|
|
49
53
|
throw new InternalServerError('Suggestions service not configured');
|
|
50
54
|
}
|
|
51
55
|
const [relativeToDid] = await ctx.hydrator.actor.getDids([params.actor]);
|
|
52
56
|
if (!relativeToDid) {
|
|
53
57
|
throw new InvalidRequestError('Actor not found');
|
|
54
58
|
}
|
|
55
|
-
const res = await
|
|
59
|
+
const res = await client.xrpc(app.bsky.unspecced.getSuggestionsSkeleton, {
|
|
56
60
|
params: {
|
|
57
61
|
viewer: params.hydrateCtx.viewer ?? undefined,
|
|
58
62
|
relativeToDid,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getSuggestedFollowsByActor.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getSuggestedFollowsByActor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAE7D,OAAO,EAEL,mBAAmB,EACnB,mBAAmB,GAEpB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAKL,cAAc,GACf,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAA;AAE1E,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,0BAA0B,GAAG,cAAc,CAC/C,QAAQ,EACR,SAAS,EACT,eAAe,EACf,YAAY,CACb,CAAA;IACD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,0BAA0B,EAAE;QACpD,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,gBAAgB;QACvC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;YAC/C,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;gBAClD,QAAQ;gBACR,MAAM;gBACN,QAAQ,EAAE,GAAG,CAAC,kBAAkB,CAAC,KAAK,CACpC,GAAG,CAAC,kBAAkB,CAAC,2BAA2B,CAAC;oBACjD,MAAM;oBACN,GAAG;iBACJ,CAAC,CACH;aACF,CAAC,CAAA;YAEF,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"getSuggestedFollowsByActor.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/graph/getSuggestedFollowsByActor.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined, noUndefinedVals } from '@atproto/common'\nimport type { Client, DidString } from '@atproto/lex'\nimport {\n type Headers as HeadersMap,\n InternalServerError,\n InvalidRequestError,\n type Server,\n} from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport type { HydrateCtx, Hydrator } from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type RulesFnInput,\n type SkeletonFnInput,\n createPipeline,\n} from '../../../../pipeline.js'\nimport { getAtprotoPassthroughHeaders } from '../../../../util/headers.js'\nimport type { Views } from '../../../../views/index.js'\nimport { resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getSuggestedFollowsByActor = createPipeline(\n skeleton,\n hydration,\n noBlocksOrMutes,\n presentation,\n )\n server.add(app.bsky.graph.getSuggestedFollowsByActor, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ auth, params, req, signal }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n labelers,\n viewer,\n features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({\n viewer,\n req,\n }),\n ),\n })\n\n const useIris = hydrateCtx.features.checkGate(\n hydrateCtx.features.Gate.SuggestedUsersIrisEnable,\n )\n const client = useIris ? ctx.irisClient : ctx.suggestionsClient\n\n if (!client) {\n return {\n encoding: 'application/json',\n body: { suggestions: [] },\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n }\n\n const headers = noUndefinedVals({\n 'accept-language': req.headers['accept-language'],\n ...getAtprotoPassthroughHeaders(req),\n })\n\n const { contentLanguage, ...body } = await getSuggestedFollowsByActor(\n { ...params, hydrateCtx, headers, signal },\n ctx,\n )\n\n return {\n encoding: 'application/json',\n body,\n headers: {\n ...(contentLanguage ? { 'content-language': contentLanguage } : null),\n ...resHeaders({ labelers: hydrateCtx.labelers }),\n },\n }\n },\n })\n}\n\nconst skeleton = async (\n input: SkeletonFnInput<Context, Params>,\n): Promise<SkeletonState> => {\n const { params, ctx } = input\n\n const useIris = params.hydrateCtx.features.checkGate(\n params.hydrateCtx.features.Gate.SuggestedUsersIrisEnable,\n )\n const client = useIris ? ctx.irisClient : ctx.suggestionsClient\n\n // handled above already, this branch should not be reached\n if (!client) {\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 = await client.xrpc(app.bsky.unspecced.getSuggestionsSkeleton, {\n params: {\n viewer: params.hydrateCtx.viewer ?? undefined,\n relativeToDid,\n },\n headers: params.headers,\n signal: params.signal,\n })\n\n return {\n recIdStr: res.body.recIdStr,\n suggestedDids: res.body.actors.map((a) => a.did),\n contentLanguage: res.headers.get('content-language') ?? undefined,\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.features.checkGate(\n params.hydrateCtx.features.Gate.SuggestedUsersSocialProofEnable,\n )\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, contentLanguage } = skeleton\n const suggestions = mapDefined(suggestedDids, (did) =>\n ctx.views.profileKnownFollowers(did, hydration),\n )\n return {\n recIdStr: skeleton.recIdStr,\n contentLanguage,\n suggestions,\n }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n suggestionsClient: Client | undefined\n irisClient: Client | undefined\n}\n\ntype Params = app.bsky.graph.getSuggestedFollowsByActor.$Params & {\n hydrateCtx: HydrateCtx\n headers: HeadersMap\n signal: AbortSignal\n}\n\ntype SkeletonState = {\n suggestedDids: DidString[]\n recIdStr?: string\n contentLanguage?: string\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getOnboardingSuggestedStarterPacks.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6B,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAiBxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"getOnboardingSuggestedStarterPacks.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6B,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAiBxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAsCvD"}
|
|
@@ -12,7 +12,11 @@ export default function (server, ctx) {
|
|
|
12
12
|
handler: async ({ auth, params, req, signal }) => {
|
|
13
13
|
const viewer = auth.credentials.iss;
|
|
14
14
|
const labelers = ctx.reqLabelers(req);
|
|
15
|
-
const hydrateCtx = await ctx.hydrator.createContext({
|
|
15
|
+
const hydrateCtx = await ctx.hydrator.createContext({
|
|
16
|
+
labelers,
|
|
17
|
+
viewer,
|
|
18
|
+
features: ctx.featureGatesClient.scope(ctx.featureGatesClient.parseUserContextFromHandler({ viewer, req })),
|
|
19
|
+
});
|
|
16
20
|
const headers = noUndefinedVals({
|
|
17
21
|
'accept-language': req.headers['accept-language'],
|
|
18
22
|
...getAtprotoPassthroughHeaders(req),
|
|
@@ -32,11 +36,14 @@ export default function (server, ctx) {
|
|
|
32
36
|
}
|
|
33
37
|
const skeleton = async (input) => {
|
|
34
38
|
const { params, ctx } = input;
|
|
35
|
-
|
|
39
|
+
const useIris = params.hydrateCtx.features.checkGate(params.hydrateCtx.features.Gate.SuggestedStarterPacksOnboardingV2Enable);
|
|
40
|
+
const client = useIris ? ctx.irisClient : ctx.topicsClient;
|
|
41
|
+
if (!client) {
|
|
36
42
|
// Use 501 instead of 500 as these are not considered retry-able by clients
|
|
37
|
-
|
|
43
|
+
const agent = useIris ? 'Iris' : 'Topics';
|
|
44
|
+
throw new MethodNotImplementedError(`${agent} agent not available`);
|
|
38
45
|
}
|
|
39
|
-
const skeleton = await
|
|
46
|
+
const skeleton = await client.call(app.bsky.unspecced.getOnboardingSuggestedStarterPacksSkeleton, { limit: params.limit, viewer: params.hydrateCtx.viewer ?? undefined }, { headers: params.headers, signal: params.signal });
|
|
40
47
|
// @TODO Make sure upstream always provides this
|
|
41
48
|
skeleton.starterPacks ??= [];
|
|
42
49
|
return skeleton;
|
|
@@ -62,6 +69,7 @@ const noBlocks = (input) => {
|
|
|
62
69
|
}
|
|
63
70
|
const blocks = hydration.bidirectionalBlocks?.get(viewer);
|
|
64
71
|
const filteredSkeleton = {
|
|
72
|
+
...skeleton,
|
|
65
73
|
starterPacks: skeleton.starterPacks.filter((uri) => {
|
|
66
74
|
try {
|
|
67
75
|
return !blocks?.get(new AtUri(uri).did);
|
|
@@ -77,6 +85,7 @@ const presentation = (input) => {
|
|
|
77
85
|
const { ctx, skeleton, hydration } = input;
|
|
78
86
|
return {
|
|
79
87
|
starterPacks: mapDefined(skeleton.starterPacks, (uri) => ctx.views.starterPack(uri, hydration)),
|
|
88
|
+
recIdStr: skeleton.recIdStr,
|
|
80
89
|
};
|
|
81
90
|
};
|
|
82
91
|
function getUniqueDidsFromStarterPacks(starterPacks) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getOnboardingSuggestedStarterPacks.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAE7D,OAAO,EAAE,KAAK,EAAoC,MAAM,iBAAiB,CAAA;AACzE,OAAO,EAAE,yBAAyB,EAAe,MAAM,sBAAsB,CAAA;AAE7E,OAAO,EAGL,eAAe,GAChB,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAKL,cAAc,GACf,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAA;AAG1E,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,kCAAkC,GAAG,cAAc,CACvD,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAY,CACb,CAAA;IACD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,kCAAkC,EAAE;QAChE,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,gBAAgB;QACvC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;YAC/C,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,
|
|
1
|
+
{"version":3,"file":"getOnboardingSuggestedStarterPacks.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined, noUndefinedVals } from '@atproto/common'\nimport type { Client } from '@atproto/lex'\nimport { AtUri, type AtUriString, type DidString } from '@atproto/syntax'\nimport { MethodNotImplementedError, type Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport {\n type HydrateCtx,\n type Hydrator,\n mergeManyStates,\n} from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport {\n type HydrationFn,\n type PresentationFn,\n type RulesFn,\n type SkeletonFn,\n createPipeline,\n} from '../../../../pipeline.js'\nimport { getAtprotoPassthroughHeaders } from '../../../../util/headers.js'\nimport type { Views } from '../../../../views/index.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getOnboardingSuggestedStarterPacks = createPipeline(\n skeleton,\n hydration,\n noBlocks,\n presentation,\n )\n server.add(app.bsky.unspecced.getOnboardingSuggestedStarterPacks, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ auth, params, req, signal }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n labelers,\n viewer,\n features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({ viewer, req }),\n ),\n })\n const headers = noUndefinedVals({\n 'accept-language': req.headers['accept-language'],\n ...getAtprotoPassthroughHeaders(req),\n })\n const result = await getOnboardingSuggestedStarterPacks(\n {\n ...params,\n hydrateCtx,\n headers,\n signal,\n },\n ctx,\n )\n return {\n encoding: 'application/json',\n body: result,\n }\n },\n })\n}\n\nconst skeleton: SkeletonFn<Context, Params, SkeletonState> = async (\n input,\n): Promise<SkeletonState> => {\n const { params, ctx } = input\n\n const useIris = params.hydrateCtx.features.checkGate(\n params.hydrateCtx.features.Gate.SuggestedStarterPacksOnboardingV2Enable,\n )\n const client = useIris ? ctx.irisClient : ctx.topicsClient\n\n if (!client) {\n // Use 501 instead of 500 as these are not considered retry-able by clients\n const agent = useIris ? 'Iris' : 'Topics'\n throw new MethodNotImplementedError(`${agent} agent not available`)\n }\n\n const skeleton = await client.call(\n app.bsky.unspecced.getOnboardingSuggestedStarterPacksSkeleton,\n { limit: params.limit, viewer: params.hydrateCtx.viewer ?? undefined },\n { headers: params.headers, signal: params.signal },\n )\n\n // @TODO Make sure upstream always provides this\n skeleton.starterPacks ??= []\n\n return skeleton\n}\n\nconst hydration: HydrationFn<Context, Params, SkeletonState> = async (\n input,\n) => {\n const { ctx, params, skeleton } = input\n\n const pairs: Map<DidString, DidString[]> = new Map()\n const viewer = params.hydrateCtx.viewer\n if (viewer) {\n pairs.set(viewer, getUniqueDidsFromStarterPacks(skeleton.starterPacks))\n }\n const [starterPacksState, bidirectionalBlocks] = await Promise.all([\n ctx.hydrator.hydrateStarterPacks(skeleton.starterPacks, params.hydrateCtx),\n ctx.hydrator.hydrateBidirectionalBlocks(pairs, params.hydrateCtx),\n ])\n\n return mergeManyStates(starterPacksState, { bidirectionalBlocks })\n}\n\nconst noBlocks: RulesFn<Context, Params, SkeletonState> = (input) => {\n const { skeleton, params, hydration } = input\n const viewer = params.hydrateCtx.viewer\n if (!viewer) {\n return skeleton\n }\n\n const blocks = hydration.bidirectionalBlocks?.get(viewer)\n const filteredSkeleton: SkeletonState = {\n ...skeleton,\n starterPacks: skeleton.starterPacks.filter((uri) => {\n try {\n return !blocks?.get(new AtUri(uri).did)\n } catch {\n return false\n }\n }),\n }\n\n return filteredSkeleton\n}\n\nconst presentation: PresentationFn<\n Context,\n Params,\n SkeletonState,\n app.bsky.unspecced.getOnboardingSuggestedStarterPacks.$OutputBody\n> = (input) => {\n const { ctx, skeleton, hydration } = input\n\n return {\n starterPacks: mapDefined(skeleton.starterPacks, (uri) =>\n ctx.views.starterPack(uri, hydration),\n ),\n recIdStr: skeleton.recIdStr,\n }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n topicsClient: Client | undefined\n irisClient: Client | undefined\n}\n\ntype Params = app.bsky.unspecced.getOnboardingSuggestedStarterPacks.$Params & {\n hydrateCtx: HydrateCtx\n headers: Record<string, string>\n signal: AbortSignal\n}\n\ntype SkeletonState =\n app.bsky.unspecced.getOnboardingSuggestedStarterPacksSkeleton.$OutputBody\n\nfunction getUniqueDidsFromStarterPacks(\n starterPacks?: AtUriString[],\n): DidString[] {\n if (!starterPacks) return []\n\n const dids = new Set<DidString>()\n\n for (const uri of starterPacks) {\n try {\n dids.add(new AtUri(uri).did)\n } catch {\n continue\n }\n }\n\n return Array.from(dids)\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getSuggestedFeeds.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/unspecced/getSuggestedFeeds.ts"],"names":[],"mappings":"AAEA,OAAO,EAA6B,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAaxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"getSuggestedFeeds.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/unspecced/getSuggestedFeeds.ts"],"names":[],"mappings":"AAEA,OAAO,EAA6B,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAaxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAiCvD"}
|
|
@@ -10,7 +10,11 @@ export default function (server, ctx) {
|
|
|
10
10
|
handler: async ({ auth, params, req, signal }) => {
|
|
11
11
|
const viewer = auth.credentials.iss;
|
|
12
12
|
const labelers = ctx.reqLabelers(req);
|
|
13
|
-
const hydrateCtx = await ctx.hydrator.createContext({
|
|
13
|
+
const hydrateCtx = await ctx.hydrator.createContext({
|
|
14
|
+
labelers,
|
|
15
|
+
viewer,
|
|
16
|
+
features: ctx.featureGatesClient.scope(ctx.featureGatesClient.parseUserContextFromHandler({ viewer, req })),
|
|
17
|
+
});
|
|
14
18
|
const headers = noUndefinedVals({
|
|
15
19
|
'accept-language': req.headers['accept-language'],
|
|
16
20
|
...getAtprotoPassthroughHeaders(req),
|
|
@@ -30,11 +34,14 @@ export default function (server, ctx) {
|
|
|
30
34
|
}
|
|
31
35
|
const skeleton = async (input) => {
|
|
32
36
|
const { params, ctx } = input;
|
|
33
|
-
|
|
37
|
+
const useIris = params.hydrateCtx.features.checkGate(params.hydrateCtx.features.Gate.SuggestedFeedsV2Enable);
|
|
38
|
+
const client = useIris ? ctx.irisClient : ctx.topicsClient;
|
|
39
|
+
if (!client) {
|
|
34
40
|
// Use 501 instead of 500 as these are not considered retry-able by clients
|
|
35
|
-
|
|
41
|
+
const agent = useIris ? 'Iris' : 'Topics';
|
|
42
|
+
throw new MethodNotImplementedError(`${agent} agent not available`);
|
|
36
43
|
}
|
|
37
|
-
return
|
|
44
|
+
return client.call(app.bsky.unspecced.getSuggestedFeedsSkeleton, {
|
|
38
45
|
limit: params.limit,
|
|
39
46
|
viewer: params.hydrateCtx.viewer ?? undefined,
|
|
40
47
|
}, {
|
|
@@ -50,6 +57,7 @@ const presentation = (input) => {
|
|
|
50
57
|
const { ctx, skeleton, hydration } = input;
|
|
51
58
|
return {
|
|
52
59
|
feeds: mapDefined(skeleton.feeds, (uri) => ctx.views.feedGenerator(uri, hydration)),
|
|
60
|
+
recIdStr: skeleton.recIdStr,
|
|
53
61
|
};
|
|
54
62
|
};
|
|
55
63
|
//# sourceMappingURL=getSuggestedFeeds.js.map
|