@atproto/bsky 0.1.6 → 0.2.0
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 +58 -0
- package/dist/api/app/bsky/actor/getProfile.js +1 -1
- package/dist/api/app/bsky/actor/getProfile.js.map +1 -1
- package/dist/api/app/bsky/actor/getProfiles.js +1 -1
- package/dist/api/app/bsky/actor/getProfiles.js.map +1 -1
- package/dist/api/app/bsky/actor/getSuggestions.js +2 -2
- package/dist/api/app/bsky/actor/getSuggestions.js.map +1 -1
- package/dist/api/app/bsky/embed/getEmbedExternalView.d.ts.map +1 -1
- package/dist/api/app/bsky/embed/getEmbedExternalView.js +132 -53
- package/dist/api/app/bsky/embed/getEmbedExternalView.js.map +1 -1
- package/dist/api/app/bsky/feed/getAuthorFeed.d.ts.map +1 -1
- package/dist/api/app/bsky/feed/getAuthorFeed.js +4 -2
- package/dist/api/app/bsky/feed/getAuthorFeed.js.map +1 -1
- package/dist/api/app/bsky/graph/getSuggestedFollowsByActor.js +2 -2
- package/dist/api/app/bsky/graph/getSuggestedFollowsByActor.js.map +1 -1
- package/dist/api/app/bsky/notification/constants.d.ts +4 -1
- package/dist/api/app/bsky/notification/constants.d.ts.map +1 -1
- package/dist/api/app/bsky/notification/constants.js +3 -0
- package/dist/api/app/bsky/notification/constants.js.map +1 -1
- package/dist/api/app/bsky/notification/getGroupedNotifications.js +19 -7
- package/dist/api/app/bsky/notification/getGroupedNotifications.js.map +1 -1
- package/dist/api/app/bsky/notification/grouping/spotlight.d.ts +1 -1
- package/dist/api/app/bsky/notification/grouping/spotlight.d.ts.map +1 -1
- package/dist/api/app/bsky/notification/grouping/spotlight.js +114 -80
- package/dist/api/app/bsky/notification/grouping/spotlight.js.map +1 -1
- package/dist/api/app/bsky/notification/listActivitySubscriptions.js +3 -2
- package/dist/api/app/bsky/notification/listActivitySubscriptions.js.map +1 -1
- package/dist/api/app/bsky/unspecced/getAtmosphereExploreTab.d.ts +4 -0
- package/dist/api/app/bsky/unspecced/getAtmosphereExploreTab.d.ts.map +1 -0
- package/dist/api/app/bsky/unspecced/getAtmosphereExploreTab.js +142 -0
- package/dist/api/app/bsky/unspecced/getAtmosphereExploreTab.js.map +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +2 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/internal/bsky/actor/getProfiles.js +4 -1
- package/dist/api/internal/bsky/actor/getProfiles.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -0
- package/dist/config.js.map +1 -1
- package/dist/data-plane/server/indexing/index.d.ts +3 -1
- package/dist/data-plane/server/indexing/index.d.ts.map +1 -1
- package/dist/data-plane/server/indexing/index.js +2 -0
- package/dist/data-plane/server/indexing/index.js.map +1 -1
- package/dist/data-plane/server/indexing/plugins/profile-link.d.ts +8 -0
- package/dist/data-plane/server/indexing/plugins/profile-link.d.ts.map +1 -0
- package/dist/data-plane/server/indexing/plugins/profile-link.js +30 -0
- package/dist/data-plane/server/indexing/plugins/profile-link.js.map +1 -0
- package/dist/data-plane/server/routes/records.d.ts.map +1 -1
- package/dist/data-plane/server/routes/records.js +1 -0
- package/dist/data-plane/server/routes/records.js.map +1 -1
- package/dist/hydration/actor.d.ts +4 -1
- package/dist/hydration/actor.d.ts.map +1 -1
- package/dist/hydration/actor.js +11 -0
- package/dist/hydration/actor.js.map +1 -1
- package/dist/hydration/external.d.ts +74 -70
- package/dist/hydration/external.d.ts.map +1 -1
- package/dist/hydration/external.js +79 -133
- package/dist/hydration/external.js.map +1 -1
- package/dist/hydration/hydrator.d.ts +57 -14
- package/dist/hydration/hydrator.d.ts.map +1 -1
- package/dist/hydration/hydrator.js +417 -105
- package/dist/hydration/hydrator.js.map +1 -1
- package/dist/lexicons/app/bsky/actor/defs.defs.d.ts +24 -0
- package/dist/lexicons/app/bsky/actor/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/actor/defs.defs.js +13 -0
- package/dist/lexicons/app/bsky/actor/defs.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/actor/link.d.ts +3 -0
- package/dist/lexicons/app/bsky/actor/link.d.ts.map +1 -0
- package/dist/lexicons/app/bsky/actor/link.defs.d.ts +105 -0
- package/dist/lexicons/app/bsky/actor/link.defs.d.ts.map +1 -0
- package/dist/lexicons/app/bsky/actor/link.defs.js +34 -0
- package/dist/lexicons/app/bsky/actor/link.defs.js.map +1 -0
- package/dist/lexicons/app/bsky/actor/link.js +6 -0
- package/dist/lexicons/app/bsky/actor/link.js.map +1 -0
- package/dist/lexicons/app/bsky/actor/profile.defs.d.ts +14 -0
- package/dist/lexicons/app/bsky/actor/profile.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/actor/profile.defs.js +3 -0
- package/dist/lexicons/app/bsky/actor/profile.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/actor.d.ts +1 -0
- package/dist/lexicons/app/bsky/actor.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/actor.js +1 -0
- package/dist/lexicons/app/bsky/actor.js.map +1 -1
- package/dist/lexicons/app/bsky/authFullApp.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/authFullApp.defs.js +1 -0
- package/dist/lexicons/app/bsky/authFullApp.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/authManageProfile.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/authManageProfile.defs.js +1 -0
- package/dist/lexicons/app/bsky/authManageProfile.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/embed/external.defs.d.ts +130 -0
- package/dist/lexicons/app/bsky/embed/external.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/embed/external.defs.js +135 -0
- package/dist/lexicons/app/bsky/embed/external.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/embed/getEmbedExternalView.defs.d.ts +15 -3
- package/dist/lexicons/app/bsky/embed/getEmbedExternalView.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/embed/getEmbedExternalView.defs.js +18 -3
- package/dist/lexicons/app/bsky/embed/getEmbedExternalView.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/notification/getGroupedNotifications.defs.d.ts +62 -3
- package/dist/lexicons/app/bsky/notification/getGroupedNotifications.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/notification/getGroupedNotifications.defs.js +53 -2
- package/dist/lexicons/app/bsky/notification/getGroupedNotifications.defs.js.map +1 -1
- package/dist/lexicons/app/bsky/unspecced/getAtmosphereExploreTab.d.ts +3 -0
- package/dist/lexicons/app/bsky/unspecced/getAtmosphereExploreTab.d.ts.map +1 -0
- package/dist/lexicons/app/bsky/unspecced/getAtmosphereExploreTab.defs.d.ts +103 -0
- package/dist/lexicons/app/bsky/unspecced/getAtmosphereExploreTab.defs.d.ts.map +1 -0
- package/dist/lexicons/app/bsky/unspecced/getAtmosphereExploreTab.defs.js +95 -0
- package/dist/lexicons/app/bsky/unspecced/getAtmosphereExploreTab.defs.js.map +1 -0
- package/dist/lexicons/app/bsky/unspecced/getAtmosphereExploreTab.js +6 -0
- package/dist/lexicons/app/bsky/unspecced/getAtmosphereExploreTab.js.map +1 -0
- package/dist/lexicons/app/bsky/unspecced.d.ts +1 -0
- package/dist/lexicons/app/bsky/unspecced.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/unspecced.js +1 -0
- package/dist/lexicons/app/bsky/unspecced.js.map +1 -1
- package/dist/lexicons/index.d.ts +2 -0
- package/dist/lexicons/index.d.ts.map +1 -1
- package/dist/lexicons/index.js +2 -0
- package/dist/lexicons/index.js.map +1 -1
- package/dist/lexicons/place/stream/badge/defs.d.ts +2 -0
- package/dist/lexicons/place/stream/badge/defs.d.ts.map +1 -0
- package/dist/lexicons/place/stream/badge/defs.defs.d.ts +131 -0
- package/dist/lexicons/place/stream/badge/defs.defs.d.ts.map +1 -0
- package/dist/lexicons/place/stream/badge/defs.defs.js +73 -0
- package/dist/lexicons/place/stream/badge/defs.defs.js.map +1 -0
- package/dist/lexicons/place/stream/badge/defs.js +5 -0
- package/dist/lexicons/place/stream/badge/defs.js.map +1 -0
- package/dist/lexicons/place/stream/badge.d.ts +2 -0
- package/dist/lexicons/place/stream/badge.d.ts.map +1 -0
- package/dist/lexicons/place/stream/badge.js +5 -0
- package/dist/lexicons/place/stream/badge.js.map +1 -0
- package/dist/lexicons/place/stream/chat/defs.d.ts +2 -0
- package/dist/lexicons/place/stream/chat/defs.d.ts.map +1 -0
- package/dist/lexicons/place/stream/chat/defs.defs.d.ts +44 -0
- package/dist/lexicons/place/stream/chat/defs.defs.d.ts.map +1 -0
- package/dist/lexicons/place/stream/chat/defs.defs.js +41 -0
- package/dist/lexicons/place/stream/chat/defs.defs.js.map +1 -0
- package/dist/lexicons/place/stream/chat/defs.js +5 -0
- package/dist/lexicons/place/stream/chat/defs.js.map +1 -0
- package/dist/lexicons/place/stream/chat/pinnedRecord.d.ts +3 -0
- package/dist/lexicons/place/stream/chat/pinnedRecord.d.ts.map +1 -0
- package/dist/lexicons/place/stream/chat/pinnedRecord.defs.d.ts +108 -0
- package/dist/lexicons/place/stream/chat/pinnedRecord.defs.d.ts.map +1 -0
- package/dist/lexicons/place/stream/chat/pinnedRecord.defs.js +31 -0
- package/dist/lexicons/place/stream/chat/pinnedRecord.defs.js.map +1 -0
- package/dist/lexicons/place/stream/chat/pinnedRecord.js +6 -0
- package/dist/lexicons/place/stream/chat/pinnedRecord.js.map +1 -0
- package/dist/lexicons/place/stream/chat/profile.d.ts +3 -0
- package/dist/lexicons/place/stream/chat/profile.d.ts.map +1 -0
- package/dist/lexicons/place/stream/chat/profile.defs.d.ts +143 -0
- package/dist/lexicons/place/stream/chat/profile.defs.d.ts.map +1 -0
- package/dist/lexicons/place/stream/chat/profile.defs.js +62 -0
- package/dist/lexicons/place/stream/chat/profile.defs.js.map +1 -0
- package/dist/lexicons/place/stream/chat/profile.js +6 -0
- package/dist/lexicons/place/stream/chat/profile.js.map +1 -0
- package/dist/lexicons/place/stream/chat.d.ts +4 -0
- package/dist/lexicons/place/stream/chat.d.ts.map +1 -0
- package/dist/lexicons/place/stream/chat.js +7 -0
- package/dist/lexicons/place/stream/chat.js.map +1 -0
- package/dist/lexicons/place/stream/defs.d.ts +2 -0
- package/dist/lexicons/place/stream/defs.d.ts.map +1 -0
- package/dist/lexicons/place/stream/defs.defs.d.ts +54 -0
- package/dist/lexicons/place/stream/defs.defs.d.ts.map +1 -0
- package/dist/lexicons/place/stream/defs.defs.js +40 -0
- package/dist/lexicons/place/stream/defs.defs.js.map +1 -0
- package/dist/lexicons/place/stream/defs.js +5 -0
- package/dist/lexicons/place/stream/defs.js.map +1 -0
- package/dist/lexicons/place/stream/livestream.d.ts +3 -0
- package/dist/lexicons/place/stream/livestream.d.ts.map +1 -0
- package/dist/lexicons/place/stream/livestream.defs.d.ts +312 -0
- package/dist/lexicons/place/stream/livestream.defs.d.ts.map +1 -0
- package/dist/lexicons/place/stream/livestream.defs.js +105 -0
- package/dist/lexicons/place/stream/livestream.defs.js.map +1 -0
- package/dist/lexicons/place/stream/livestream.js +6 -0
- package/dist/lexicons/place/stream/livestream.js.map +1 -0
- package/dist/lexicons/place/stream.d.ts +5 -0
- package/dist/lexicons/place/stream.d.ts.map +1 -0
- package/dist/lexicons/place/stream.js +8 -0
- package/dist/lexicons/place/stream.js.map +1 -0
- package/dist/lexicons/place.d.ts +2 -0
- package/dist/lexicons/place.d.ts.map +1 -0
- package/dist/lexicons/place.js +5 -0
- package/dist/lexicons/place.js.map +1 -0
- package/dist/lexicons/site/standard/document.defs.d.ts +127 -127
- package/dist/lexicons/site/standard/document.defs.d.ts.map +1 -1
- package/dist/lexicons/site/standard/document.defs.js +28 -28
- package/dist/lexicons/site/standard/document.defs.js.map +1 -1
- package/dist/lexicons/site/standard/graph/recommend.defs.d.ts +11 -11
- package/dist/lexicons/site/standard/graph/recommend.defs.d.ts.map +1 -1
- package/dist/lexicons/site/standard/graph/recommend.defs.js +1 -1
- package/dist/lexicons/site/standard/graph/recommend.defs.js.map +1 -1
- package/dist/lexicons/site/standard/publication.defs.d.ts +52 -52
- package/dist/lexicons/site/standard/publication.defs.d.ts.map +1 -1
- package/dist/lexicons/site/standard/publication.defs.js +6 -6
- package/dist/lexicons/site/standard/publication.defs.js.map +1 -1
- package/dist/lexicons/site/standard/theme/basic.defs.d.ts +14 -14
- package/dist/lexicons/site/standard/theme/basic.defs.d.ts.map +1 -1
- package/dist/lexicons/site/standard/theme/basic.defs.js +1 -1
- package/dist/lexicons/site/standard/theme/basic.defs.js.map +1 -1
- package/dist/lexicons/social/grain/defs.d.ts +2 -0
- package/dist/lexicons/social/grain/defs.d.ts.map +1 -0
- package/dist/lexicons/social/grain/defs.defs.d.ts +15 -0
- package/dist/lexicons/social/grain/defs.defs.d.ts.map +1 -0
- package/dist/lexicons/social/grain/defs.defs.js +14 -0
- package/dist/lexicons/social/grain/defs.defs.js.map +1 -0
- package/dist/lexicons/social/grain/defs.js +5 -0
- package/dist/lexicons/social/grain/defs.js.map +1 -0
- package/dist/lexicons/social/grain/favorite.d.ts +3 -0
- package/dist/lexicons/social/grain/favorite.d.ts.map +1 -0
- package/dist/lexicons/social/grain/favorite.defs.d.ts +72 -0
- package/dist/lexicons/social/grain/favorite.defs.d.ts.map +1 -0
- package/dist/lexicons/social/grain/favorite.defs.js +26 -0
- package/dist/lexicons/social/grain/favorite.defs.js.map +1 -0
- package/dist/lexicons/social/grain/favorite.js +6 -0
- package/dist/lexicons/social/grain/favorite.js.map +1 -0
- package/dist/lexicons/social/grain/gallery/item.d.ts +3 -0
- package/dist/lexicons/social/grain/gallery/item.d.ts.map +1 -0
- package/dist/lexicons/social/grain/gallery/item.defs.d.ts +94 -0
- package/dist/lexicons/social/grain/gallery/item.defs.d.ts.map +1 -0
- package/dist/lexicons/social/grain/gallery/item.defs.js +29 -0
- package/dist/lexicons/social/grain/gallery/item.defs.js.map +1 -0
- package/dist/lexicons/social/grain/gallery/item.js +6 -0
- package/dist/lexicons/social/grain/gallery/item.js.map +1 -0
- package/dist/lexicons/social/grain/gallery.d.ts +4 -0
- package/dist/lexicons/social/grain/gallery.d.ts.map +1 -0
- package/dist/lexicons/social/grain/gallery.defs.d.ts +98 -0
- package/dist/lexicons/social/grain/gallery.defs.d.ts.map +1 -0
- package/dist/lexicons/social/grain/gallery.defs.js +33 -0
- package/dist/lexicons/social/grain/gallery.defs.js.map +1 -0
- package/dist/lexicons/social/grain/gallery.js +7 -0
- package/dist/lexicons/social/grain/gallery.js.map +1 -0
- package/dist/lexicons/social/grain/photo.d.ts +3 -0
- package/dist/lexicons/social/grain/photo.d.ts.map +1 -0
- package/dist/lexicons/social/grain/photo.defs.d.ts +98 -0
- package/dist/lexicons/social/grain/photo.defs.d.ts.map +1 -0
- package/dist/lexicons/social/grain/photo.defs.js +31 -0
- package/dist/lexicons/social/grain/photo.defs.js.map +1 -0
- package/dist/lexicons/social/grain/photo.js +6 -0
- package/dist/lexicons/social/grain/photo.js.map +1 -0
- package/dist/lexicons/social/grain.d.ts +5 -0
- package/dist/lexicons/social/grain.d.ts.map +1 -0
- package/dist/lexicons/social/grain.js +8 -0
- package/dist/lexicons/social/grain.js.map +1 -0
- package/dist/lexicons/social.d.ts +2 -0
- package/dist/lexicons/social.d.ts.map +1 -0
- package/dist/lexicons/social.js +5 -0
- package/dist/lexicons/social.js.map +1 -0
- package/dist/proto/bsky_connect.d.ts +10 -1
- package/dist/proto/bsky_connect.d.ts.map +1 -1
- package/dist/proto/bsky_connect.js +10 -1
- package/dist/proto/bsky_connect.js.map +1 -1
- package/dist/proto/bsky_pb.d.ts +34 -0
- package/dist/proto/bsky_pb.d.ts.map +1 -1
- package/dist/proto/bsky_pb.js +60 -0
- package/dist/proto/bsky_pb.js.map +1 -1
- package/dist/telemetry/events.d.ts +30 -0
- package/dist/telemetry/events.d.ts.map +1 -1
- package/dist/telemetry/events.js +37 -0
- package/dist/telemetry/events.js.map +1 -1
- package/dist/util/external/index.d.ts +8 -0
- package/dist/util/external/index.d.ts.map +1 -0
- package/dist/util/external/index.js +50 -0
- package/dist/util/external/index.js.map +1 -0
- package/dist/util/{standard-site.d.ts → external/standard-site.d.ts} +30 -4
- package/dist/util/external/standard-site.d.ts.map +1 -0
- package/dist/util/{standard-site.js → external/standard-site.js} +73 -4
- package/dist/util/external/standard-site.js.map +1 -0
- package/dist/views/external.d.ts +8 -0
- package/dist/views/external.d.ts.map +1 -0
- package/dist/views/external.js +260 -0
- package/dist/views/external.js.map +1 -0
- package/dist/views/index.d.ts +12 -6
- package/dist/views/index.d.ts.map +1 -1
- package/dist/views/index.js +89 -42
- package/dist/views/index.js.map +1 -1
- package/dist/views/profile-link-rules.d.ts +10 -0
- package/dist/views/profile-link-rules.d.ts.map +1 -0
- package/dist/views/profile-link-rules.js +48 -0
- package/dist/views/profile-link-rules.js.map +1 -0
- package/dist/views/types.d.ts +3 -0
- package/dist/views/types.d.ts.map +1 -1
- package/dist/views/types.js.map +1 -1
- package/package.json +4 -4
- package/dist/util/standard-site.d.ts.map +0 -1
- package/dist/util/standard-site.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,63 @@
|
|
|
1
1
|
# @atproto/bsky
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#5615](https://github.com/bluesky-social/atproto/pull/5615) [`a6f5a3c`](https://github.com/bluesky-social/atproto/commit/a6f5a3c7f5e294e96971810d61f23b8f5998a5e2) Thanks [@vineyardbovines](https://github.com/vineyardbovines)! - Hydrate `app.bsky.actor.link` records into `links` on detailed profile views, leaving out taken-down links and links to URL shorteners.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- [#5631](https://github.com/bluesky-social/atproto/pull/5631) [`647cb41`](https://github.com/bluesky-social/atproto/commit/647cb412576f1ba92c63aa00c71743cb400bdf8d) Thanks [@rafaeleyng](https://github.com/rafaeleyng)! - Return basic starter-pack views in grouped notifications, avoiding feed and list-member hydration.
|
|
12
|
+
|
|
13
|
+
- [#5636](https://github.com/bluesky-social/atproto/pull/5636) [`5e0e11d`](https://github.com/bluesky-social/atproto/commit/5e0e11db6d42758e4fb763bcbfb6d2affdf7b2e9) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Add the optional `BSKY_EXTERNAL_RECORDS_SAFE_DOMAINS` comma-separated setting, exposed as `ServerConfig.externalRecordsSafeDomains`, which defaults to an empty list.
|
|
14
|
+
|
|
15
|
+
- [#5638](https://github.com/bluesky-social/atproto/pull/5638) [`ba08e05`](https://github.com/bluesky-social/atproto/commit/ba08e05d86f7cdb71ea11d2b620ac2d7eec6b532) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Make external view dependency hydration best effort.
|
|
16
|
+
|
|
17
|
+
- [#5631](https://github.com/bluesky-social/atproto/pull/5631) [`647cb41`](https://github.com/bluesky-social/atproto/commit/647cb412576f1ba92c63aa00c71743cb400bdf8d) Thanks [@rafaeleyng](https://github.com/rafaeleyng)! - Limit known-follower hydration in grouped notifications to the first ten actors per follow group.
|
|
18
|
+
|
|
19
|
+
- [#5635](https://github.com/bluesky-social/atproto/pull/5635) [`cffb239`](https://github.com/bluesky-social/atproto/commit/cffb239f483be851f3eb0e09243d4739f5bc9cd0) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Replace custom hydration in `getAtmosphereExploreTab` with generic external-view hydration, using the first URI in each worker group as its canonical root and discovering dependencies automatically.
|
|
20
|
+
|
|
21
|
+
- [#5636](https://github.com/bluesky-social/atproto/pull/5636) [`5e0e11d`](https://github.com/bluesky-social/atproto/commit/5e0e11db6d42758e4fb763bcbfb6d2affdf7b2e9) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Organize external hydration helpers and their specific types below the hydrator class without changing behavior.
|
|
22
|
+
|
|
23
|
+
- [#5614](https://github.com/bluesky-social/atproto/pull/5614) [`976ebfb`](https://github.com/bluesky-social/atproto/commit/976ebfb1f1c0feea00d12e3eedbcaca2a690a030) Thanks [@foysalit](https://github.com/foysalit)! - Allow the trusted moderation service to bypass actor and list blocks when fetching author feeds.
|
|
24
|
+
|
|
25
|
+
- [#5635](https://github.com/bluesky-social/atproto/pull/5635) [`cffb239`](https://github.com/bluesky-social/atproto/commit/cffb239f483be851f3eb0e09243d4739f5bc9cd0) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Refactor external record hydration into a shared, bounded pipeline for latest-URI and exact-ref lookups, including dependency discovery, moderation, deduplication, and traversal metrics for Standard Site, Grain, and Streamplace records.
|
|
26
|
+
|
|
27
|
+
- [#5636](https://github.com/bluesky-social/atproto/pull/5636) [`5e0e11d`](https://github.com/bluesky-social/atproto/commit/5e0e11db6d42758e4fb763bcbfb6d2affdf7b2e9) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Add standalone Standard.site record selection/validation and safe-domain URL matching utilities for external embeds.
|
|
28
|
+
|
|
29
|
+
- [#5638](https://github.com/bluesky-social/atproto/pull/5638) [`ba08e05`](https://github.com/bluesky-social/atproto/commit/ba08e05d86f7cdb71ea11d2b620ac2d7eec6b532) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Remove legacy Standard.site external-view hydration.
|
|
30
|
+
|
|
31
|
+
- [#5636](https://github.com/bluesky-social/atproto/pull/5636) [`5e0e11d`](https://github.com/bluesky-social/atproto/commit/5e0e11db6d42758e4fb763bcbfb6d2affdf7b2e9) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Make `app.bsky.embed.getEmbedExternalView` resolve a single canonical record (from `canonicalUri`, or normalized from the legacy `uris` input, which is now optional), validate it against the requested URL before building views, return generic `data` alongside the Standard.site-only legacy `view`, and report records that fail validation in `unverifiedAssociatedRefs`/`unverifiedAssociatedRecords`.
|
|
32
|
+
|
|
33
|
+
- [#5633](https://github.com/bluesky-social/atproto/pull/5633) [`dbb0bb5`](https://github.com/bluesky-social/atproto/commit/dbb0bb54a6228021b4169a82a3e8dbe38b42fd4c) Thanks [@rafaeleyng](https://github.com/rafaeleyng)! - Extend grouped notification spotlighting to reposts and via-repost interactions, with up to three spotlights per page.
|
|
34
|
+
|
|
35
|
+
- [#5631](https://github.com/bluesky-social/atproto/pull/5631) [`647cb41`](https://github.com/bluesky-social/atproto/commit/647cb412576f1ba92c63aa00c71743cb400bdf8d) Thanks [@rafaeleyng](https://github.com/rafaeleyng)! - Run profile hydration through a shared worker and let callers request activity-subscription state alongside profile data.
|
|
36
|
+
|
|
37
|
+
- [#5638](https://github.com/bluesky-social/atproto/pull/5638) [`ba08e05`](https://github.com/bluesky-social/atproto/commit/ba08e05d86f7cdb71ea11d2b620ac2d7eec6b532) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Delete unused legacy Standard.site URI hydration helpers.
|
|
38
|
+
|
|
39
|
+
- [#5631](https://github.com/bluesky-social/atproto/pull/5631) [`647cb41`](https://github.com/bluesky-social/atproto/commit/647cb412576f1ba92c63aa00c71743cb400bdf8d) Thanks [@rafaeleyng](https://github.com/rafaeleyng)! - Hydrate profiles and subscription settings in listActivitySubscriptions without fetching unused known followers, profile counts, or joined-via starter packs.
|
|
40
|
+
|
|
41
|
+
- [#5636](https://github.com/bluesky-social/atproto/pull/5636) [`5e0e11d`](https://github.com/bluesky-social/atproto/commit/5e0e11db6d42758e4fb763bcbfb6d2affdf7b2e9) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Keep persisted `getEmbedExternalView` associations slim: always return the canonical record, plus only an opted-in set of dependency collections (a Standard.site document's publication, a Grain gallery's items and photos). Recommendation, subscription and favorite records still back rendered previews but are no longer returned for persistence.
|
|
42
|
+
|
|
43
|
+
- [#5631](https://github.com/bluesky-social/atproto/pull/5631) [`647cb41`](https://github.com/bluesky-social/atproto/commit/647cb412576f1ba92c63aa00c71743cb400bdf8d) Thanks [@rafaeleyng](https://github.com/rafaeleyng)! - Return basic profiles with known followers in grouped notification related views, avoiding detailed-profile and activity-subscription hydration.
|
|
44
|
+
- Updated dependencies [[`d70b673`](https://github.com/bluesky-social/atproto/commit/d70b673be6bce3b6f4d7478254e359913a101c18), [`647cb41`](https://github.com/bluesky-social/atproto/commit/647cb412576f1ba92c63aa00c71743cb400bdf8d), [`5e0e11d`](https://github.com/bluesky-social/atproto/commit/5e0e11db6d42758e4fb763bcbfb6d2affdf7b2e9), [`dbb0bb5`](https://github.com/bluesky-social/atproto/commit/dbb0bb54a6228021b4169a82a3e8dbe38b42fd4c), [`647cb41`](https://github.com/bluesky-social/atproto/commit/647cb412576f1ba92c63aa00c71743cb400bdf8d)]:
|
|
45
|
+
- @atproto/api@0.25.0
|
|
46
|
+
|
|
47
|
+
## 0.1.7
|
|
48
|
+
|
|
49
|
+
### Patch Changes
|
|
50
|
+
|
|
51
|
+
- [#5617](https://github.com/bluesky-social/atproto/pull/5617) [`94e3838`](https://github.com/bluesky-social/atproto/commit/94e3838ea3bb1785a1989931a815b62b2057e5db) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Add app.bsky.unspecced.getAtmosphereExploreTab with curated CMS content, canonical external modality views, and BSKY_ATMOSPHERE_EXPLORE_TAB_SERVICE configuration. Accept optional langs, countryCode, and regionCode parameters, forwarding countryCode and regionCode to the CMS.
|
|
52
|
+
|
|
53
|
+
- [#5599](https://github.com/bluesky-social/atproto/pull/5599) [`648f7c9`](https://github.com/bluesky-social/atproto/commit/648f7c9ebff13a51341977abd7fe2f5b603a2783) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Add canonical Atmosphere modality view schemas.
|
|
54
|
+
|
|
55
|
+
- [#5607](https://github.com/bluesky-social/atproto/pull/5607) [`6831a2b`](https://github.com/bluesky-social/atproto/commit/6831a2bc6041039bef670b37da624ccb164b6231) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Determine livestream view activity from a two-minute `lastSeenAt` heartbeat window.
|
|
56
|
+
|
|
57
|
+
- [#5607](https://github.com/bluesky-social/atproto/pull/5607) [`6831a2b`](https://github.com/bluesky-social/atproto/commit/6831a2bc6041039bef670b37da624ccb164b6231) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Add article, publication, gallery, and livestream record modality view builders.
|
|
58
|
+
- Updated dependencies [[`94e3838`](https://github.com/bluesky-social/atproto/commit/94e3838ea3bb1785a1989931a815b62b2057e5db), [`648f7c9`](https://github.com/bluesky-social/atproto/commit/648f7c9ebff13a51341977abd7fe2f5b603a2783)]:
|
|
59
|
+
- @atproto/api@0.24.3
|
|
60
|
+
|
|
3
61
|
## 0.1.6
|
|
4
62
|
|
|
5
63
|
### Patch Changes
|
|
@@ -40,7 +40,7 @@ const hydration = async (input) => {
|
|
|
40
40
|
const { ctx, params, skeleton } = input;
|
|
41
41
|
return ctx.hydrator.hydrateProfilesDetailed([skeleton.did], params.hydrateCtx.copy({
|
|
42
42
|
overrideIncludeTakedownsForActor: true,
|
|
43
|
-
}));
|
|
43
|
+
}), { knownFollowersDids: [skeleton.did], activitySubscriptions: true });
|
|
44
44
|
};
|
|
45
45
|
const presentation = (input) => {
|
|
46
46
|
const { ctx, params, skeleton, hydration } = input;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getProfile.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/actor/getProfile.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAe,MAAM,sBAAsB,CAAA;AAOvE,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,UAAU,GAAG,cAAc,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,CAAA;IAC7E,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE;QACpC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,sBAAsB;QAC7C,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE;YACvC,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,GAClD,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,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,gBAAgB;gBAChB,gBAAgB;aACjB,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,EAAE,GAAG,CAAC,CAAA;YAE/D,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAA;YAE/D,OAAO;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,UAAU,CAAC;oBAClB,OAAO;oBACP,QAAQ,EAAE,UAAU,CAAC,QAAQ;iBAC9B,CAAC;aACH,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,QAAQ,GAAG,KAAK,EAAE,KAGvB,EAA0B,EAAE;IAC3B,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;IAC7B,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;IAC9D,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,mBAAmB,CAAC,mBAAmB,CAAC,CAAA;IACpD,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,CAAA;AAChB,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,KAAK,EAAE,KAIxB,EAAE,EAAE;IACH,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAA;IACvC,OAAO,GAAG,CAAC,QAAQ,CAAC,uBAAuB,CACzC,CAAC,QAAQ,CAAC,GAAG,CAAC,EACd,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;QACrB,gCAAgC,EAAE,IAAI;KACvC,CAAC,
|
|
1
|
+
{"version":3,"file":"getProfile.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/actor/getProfile.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DidString } from '@atproto/syntax'\nimport { InvalidRequestError, type Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport type {\n HydrateCtx,\n HydrationState,\n Hydrator,\n} from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport { createPipeline, noRules } from '../../../../pipeline.js'\nimport type { Views } from '../../../../views/index.js'\nimport { resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getProfile = createPipeline(skeleton, hydration, noRules, presentation)\n server.add(app.bsky.actor.getProfile, {\n auth: ctx.authVerifier.optionalStandardOrRole,\n handler: async ({ auth, params, req }) => {\n const { viewer, includeTakedowns, skipViewerBlocks } =\n ctx.authVerifier.parseCreds(auth)\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n labelers,\n viewer,\n includeTakedowns,\n skipViewerBlocks,\n })\n\n const result = await getProfile({ ...params, hydrateCtx }, ctx)\n\n const repoRev = await ctx.hydrator.actor.getRepoRevSafe(viewer)\n\n return {\n encoding: 'application/json',\n body: result,\n headers: resHeaders({\n repoRev,\n labelers: hydrateCtx.labelers,\n }),\n }\n },\n })\n}\n\nconst skeleton = async (input: {\n ctx: Context\n params: Params\n}): Promise<SkeletonState> => {\n const { ctx, params } = input\n const [did] = await ctx.hydrator.actor.getDids([params.actor])\n if (!did) {\n throw new InvalidRequestError('Profile not found')\n }\n return { did }\n}\n\nconst hydration = async (input: {\n ctx: Context\n params: Params\n skeleton: SkeletonState\n}) => {\n const { ctx, params, skeleton } = input\n return ctx.hydrator.hydrateProfilesDetailed(\n [skeleton.did],\n params.hydrateCtx.copy({\n overrideIncludeTakedownsForActor: true,\n }),\n { knownFollowersDids: [skeleton.did], activitySubscriptions: true },\n )\n}\n\nconst presentation = (input: {\n ctx: Context\n params: Params\n skeleton: SkeletonState\n hydration: HydrationState\n}) => {\n const { ctx, params, skeleton, hydration } = input\n const profile = ctx.views.profileDetailed(skeleton.did, hydration)\n if (!profile) {\n throw new InvalidRequestError('Profile not found')\n } else if (!params.hydrateCtx.includeTakedowns) {\n if (ctx.views.actorIsTakendown(skeleton.did, hydration)) {\n throw new InvalidRequestError(\n 'Account has been suspended',\n 'AccountTakedown',\n )\n } else if (ctx.views.actorIsDeactivated(skeleton.did, hydration)) {\n throw new InvalidRequestError(\n 'Account is deactivated',\n 'AccountDeactivated',\n )\n }\n }\n return profile\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n}\n\ntype Params = app.bsky.actor.getProfile.$Params & {\n hydrateCtx: HydrateCtx\n}\n\ntype SkeletonState = { did: DidString }\n"]}
|
|
@@ -47,7 +47,7 @@ const skeleton = async (input) => {
|
|
|
47
47
|
};
|
|
48
48
|
const hydration = async (input) => {
|
|
49
49
|
const { ctx, params, skeleton } = input;
|
|
50
|
-
return ctx.hydrator.hydrateProfilesDetailed(skeleton.dids, params.hydrateCtx);
|
|
50
|
+
return ctx.hydrator.hydrateProfilesDetailed(skeleton.dids, params.hydrateCtx, { knownFollowersDids: skeleton.dids, activitySubscriptions: true });
|
|
51
51
|
};
|
|
52
52
|
const presentation = (input) => {
|
|
53
53
|
const { ctx, skeleton, hydration } = input;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getProfiles.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/actor/getProfiles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAS5C,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,MAAM,CAAC,OAAO,WAAW,MAAc,EAAE,GAAe;IACtD,MAAM,UAAU,GAAG,cAAc,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,CAAA;IAC7E,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;QACrC,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,6BAA6B,CAAC;YACnD,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;gBACnB,IAAI,CAAC,MAAM;oBAAE,OAAO,KAAK,CAAA;gBACzB,OAAO,CACL,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI;oBAC1C,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAChC,CAAA;YACH,CAAC;SACF,CAAC;QACF,IAAI,EAAE;YACJ,wEAAwE;YACxE,gHAAgH;YAChH,gBAAgB,EAAE,IAAI;SACvB;QACD,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE;YACvC,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,GAClD,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YACnC,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;YACrC,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC;gBAClD,MAAM;gBACN,QAAQ;gBACR,gBAAgB;gBAChB,gBAAgB;aACjB,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,EAAE,GAAG,CAAC,CAAA;YAE/D,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAA;YAE/D,OAAO;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,UAAU,CAAC;oBAClB,OAAO;oBACP,QAAQ,EAAE,UAAU,CAAC,QAAQ;iBAC9B,CAAC;aACH,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,QAAQ,GAAG,KAAK,EAAE,KAGvB,EAA0B,EAAE;IAC3B,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;IAC7B,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACnE,OAAO,EAAE,IAAI,EAAE,CAAA;AACjB,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,KAAK,EAAE,KAIxB,EAAE,EAAE;IACH,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAA;IACvC,OAAO,GAAG,CAAC,QAAQ,CAAC,uBAAuB,
|
|
1
|
+
{"version":3,"file":"getProfiles.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/actor/getProfiles.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined } from '@atproto/common'\nimport type { DidString } from '@atproto/syntax'\nimport type { Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport type {\n HydrateCtx,\n HydrationState,\n Hydrator,\n} from '../../../../hydration/hydrator.js'\nimport { app } from '../../../../lexicons/index.js'\nimport { createPipeline, noRules } from '../../../../pipeline.js'\nimport type { Views } from '../../../../views/index.js'\nimport { resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getProfile = createPipeline(skeleton, hydration, noRules, presentation)\n server.add(app.bsky.actor.getProfiles, {\n auth: ctx.authVerifier.standardOptionalParameterized({\n lxmCheck: (method) => {\n if (!method) return false\n return (\n method === app.bsky.actor.getProfiles.$lxm ||\n method.startsWith('chat.bsky.')\n )\n },\n }),\n opts: {\n // @TODO remove after grace period has passed, behavior is non-standard.\n // temporarily added for compat w/ previous version of xrpc-server to avoid breakage of a few specified parties.\n paramsParseLoose: true,\n },\n handler: async ({ auth, params, req }) => {\n const { viewer, includeTakedowns, skipViewerBlocks } =\n ctx.authVerifier.parseCreds(auth)\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n viewer,\n labelers,\n includeTakedowns,\n skipViewerBlocks,\n })\n\n const result = await getProfile({ ...params, hydrateCtx }, ctx)\n\n const repoRev = await ctx.hydrator.actor.getRepoRevSafe(viewer)\n\n return {\n encoding: 'application/json',\n body: result,\n headers: resHeaders({\n repoRev,\n labelers: hydrateCtx.labelers,\n }),\n }\n },\n })\n}\n\nconst skeleton = async (input: {\n ctx: Context\n params: Params\n}): Promise<SkeletonState> => {\n const { ctx, params } = input\n const dids = await ctx.hydrator.actor.getDidsDefined(params.actors)\n return { dids }\n}\n\nconst hydration = async (input: {\n ctx: Context\n params: Params\n skeleton: SkeletonState\n}) => {\n const { ctx, params, skeleton } = input\n return ctx.hydrator.hydrateProfilesDetailed(\n skeleton.dids,\n params.hydrateCtx,\n { knownFollowersDids: skeleton.dids, activitySubscriptions: true },\n )\n}\n\nconst presentation = (input: {\n ctx: Context\n params: Params\n skeleton: SkeletonState\n hydration: HydrationState\n}) => {\n const { ctx, skeleton, hydration } = input\n const profiles = mapDefined(skeleton.dids, (did) =>\n ctx.views.profileDetailed(did, hydration),\n )\n return { profiles }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n}\n\ntype Params = app.bsky.actor.getProfiles.$Params & {\n hydrateCtx: HydrateCtx\n}\n\ntype SkeletonState = { dids: DidString[] }\n"]}
|
|
@@ -86,7 +86,7 @@ const skeleton = async (input) => {
|
|
|
86
86
|
};
|
|
87
87
|
const hydration = async (input) => {
|
|
88
88
|
const { ctx, params, skeleton } = input;
|
|
89
|
-
return ctx.hydrator.hydrateProfilesDetailed(skeleton.dids, params.hydrateCtx);
|
|
89
|
+
return ctx.hydrator.hydrateProfilesDetailed(skeleton.dids, params.hydrateCtx, { knownFollowersDids: skeleton.dids, activitySubscriptions: true });
|
|
90
90
|
};
|
|
91
91
|
const noBlocksOrMutes = (input) => {
|
|
92
92
|
const { ctx, skeleton, hydration } = input;
|
|
@@ -96,7 +96,7 @@ const noBlocksOrMutes = (input) => {
|
|
|
96
96
|
};
|
|
97
97
|
const presentation = (input) => {
|
|
98
98
|
const { ctx, skeleton, hydration } = input;
|
|
99
|
-
const actors = mapDefined(skeleton.dids, (did) => ctx.views.
|
|
99
|
+
const actors = mapDefined(skeleton.dids, (did) => ctx.views.profile(did, hydration));
|
|
100
100
|
return {
|
|
101
101
|
actors,
|
|
102
102
|
cursor: skeleton.cursor,
|
|
@@ -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;gBAClD,MAAM;gBACN,QAAQ;gBACR,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,iBAAiB,EAAE,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC;gBACjD,GAAG,4BAA4B,CAAC,GAAG,CAAC;aACrC,CAAC,CAAA;YACF,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC;gBAC9D,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAC3B,cAAc,CACZ,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,EACzD,GAAG,CACJ;gBACH,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM;aACvB,CAAC,CAAA;YACF,MAAM,qBAAqB,GAAG,eAAe,CAAC;gBAC5C,kBAAkB,EAAE,aAAa,EAAE,GAAG,CAAC,kBAAkB,CAAC;aAC3D,CAAC,CAAA;YACF,OAAO;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,GAAG,qBAAqB;oBACxB,GAAG,UAAU,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAAC;iBACjD;aACF,CAAA;QACH,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,QAAQ,GAAG,KAAK,EAAE,KAGvB,EAAqB,EAAE;IACtB,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;IAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAA;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAClD,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CACzD,CAAA;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAA;IAE/D,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,sBAAsB,EAAE;YACvE,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE;gBACN,aAAa,EAAE,MAAM;gBACrB,MAAM,EAAE,MAAM,IAAI,SAAS;gBAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB;SACF,CAAC,CAAA;QACF,OAAO;YACL,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;YACvC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM;YACvB,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK;YACrB,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ;YAC3B,UAAU,EAAE,GAAG,CAAC,OAAO;SACxB,CAAA;IACH,CAAC;SAAM,CAAC;QACN,sHAAsH;QACtH,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,oBAAoB,CAAC;YAC3D,QAAQ,EAAE,MAAM,IAAI,SAAS;YAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CAAA;QACF,wCAAwC;QACxC,IAAI,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QAC/C,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,qBAAqB,CAAC;gBACxD,QAAQ,EAAE,MAAM;gBAChB,UAAU,EAAE,IAAI;aACjB,CAAC,CAAA;YACF,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,MAAM,CAAC,CAAA;QACpE,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAA;IAC1D,CAAC;AACH,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,KAAK,EAAE,KAIxB,EAAE,EAAE;IACH,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAA;IACvC,OAAO,GAAG,CAAC,QAAQ,CAAC,uBAAuB,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;AAC/E,CAAC,CAAA;AAED,MAAM,eAAe,GAAG,CAAC,KAKxB,EAAE,EAAE;IACH,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,KAAK,CAAA;IAC1C,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAClC,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,CAAC,KAKrB,EAAE,EAAE;IACH,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,KAAK,CAAA;IAC1C,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAC/C,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC,GAAG,EAAE,SAAS,CAAC,CAChD,CAAA;IACD,OAAO;QACL,MAAM;QACN,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,UAAU,EAAE,QAAQ,CAAC,UAAU;KAChC,CAAA;AACH,CAAC,CAAA","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
|
+
{"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(\n skeleton.dids,\n params.hydrateCtx,\n { knownFollowersDids: skeleton.dids, activitySubscriptions: true },\n )\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.profile(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":"getEmbedExternalView.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/embed/getEmbedExternalView.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"getEmbedExternalView.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/embed/getEmbedExternalView.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAElD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAuBxD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QAqBvD"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { isDidString, } from '@atproto/lex';
|
|
2
|
+
import { parseAtUriString } from '@atproto/syntax';
|
|
3
|
+
import { app, com, site, social } from '../../../../lexicons/index.js';
|
|
3
4
|
import { createPipeline, noRules, } from '../../../../pipeline.js';
|
|
5
|
+
import { isExternalRecordUrlSafe } from '../../../../util/external/index.js';
|
|
6
|
+
import { getStandardSiteRecordsForUri, validateStandardSiteRecordsForUrl, } from '../../../../util/external/standard-site.js';
|
|
4
7
|
import { resHeaders } from '../../../util.js';
|
|
5
8
|
export default function (server, ctx) {
|
|
6
9
|
const getEmbedExternalView = createPipeline(skeleton, hydration, noRules, presentation);
|
|
@@ -20,67 +23,143 @@ export default function (server, ctx) {
|
|
|
20
23
|
});
|
|
21
24
|
}
|
|
22
25
|
const skeleton = async (inputs) => {
|
|
23
|
-
return {
|
|
26
|
+
return { canonicalUri: normalizeCanonicalUri(inputs.params) };
|
|
24
27
|
};
|
|
25
28
|
const hydration = async (inputs) => {
|
|
26
29
|
const { ctx, params, skeleton } = inputs;
|
|
27
|
-
|
|
30
|
+
if (!skeleton.canonicalUri)
|
|
31
|
+
return { ctx: params.hydrateCtx };
|
|
32
|
+
return ctx.hydrator.hydrateEmbedExternalViewFromUris([skeleton.canonicalUri], params.hydrateCtx);
|
|
28
33
|
};
|
|
29
34
|
const presentation = (inputs) => {
|
|
30
|
-
const { hydration } = inputs;
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
const { ctx, params, skeleton, hydration } = inputs;
|
|
36
|
+
const { canonicalUri } = skeleton;
|
|
37
|
+
if (!canonicalUri)
|
|
38
|
+
return {};
|
|
39
|
+
if (!hydration.externalRecords?.get(canonicalUri))
|
|
40
|
+
return {};
|
|
41
|
+
const { associatedRefs, associatedRecords } = collectAssociations(canonicalUri, hydration.externalRecords);
|
|
42
|
+
// Validate before building any view: trust must not depend on whether the
|
|
43
|
+
// records happen to be renderable.
|
|
44
|
+
const standardSite = isStandardSiteUri(canonicalUri);
|
|
45
|
+
const standardSiteRecords = standardSite
|
|
46
|
+
? getStandardSiteRecordsForUri(canonicalUri, hydration.externalRecords)
|
|
47
|
+
: undefined;
|
|
48
|
+
const verified = standardSiteRecords
|
|
49
|
+
? validateStandardSiteRecordsForUrl(standardSiteRecords.document, standardSiteRecords.publication, params.url)
|
|
50
|
+
: isExternalRecordUrlSafe(params.url, ctx.cfg.externalRecordsSafeDomains);
|
|
51
|
+
if (!verified) {
|
|
52
|
+
return {
|
|
53
|
+
unverifiedAssociatedRefs: associatedRefs,
|
|
54
|
+
unverifiedAssociatedRecords: associatedRecords,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const data = ctx.views.externalRecordView(canonicalUri, hydration);
|
|
58
|
+
let view;
|
|
59
|
+
if (standardSiteRecords) {
|
|
60
|
+
const standardSiteView = ctx.views.externalEmbedFromStandardSiteRecords({
|
|
61
|
+
document: standardSiteRecords.document,
|
|
62
|
+
publication: standardSiteRecords.publication,
|
|
63
|
+
state: hydration,
|
|
64
|
+
assumedUrl: params.url,
|
|
65
|
+
});
|
|
66
|
+
if (standardSiteView) {
|
|
67
|
+
view = app.bsky.embed.external.view.$build({
|
|
68
|
+
external: {
|
|
69
|
+
...standardSiteView,
|
|
70
|
+
uri: params.url,
|
|
71
|
+
associatedRefs: associatedRefs,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
view,
|
|
78
|
+
data,
|
|
79
|
+
associatedRefs: associatedRefs,
|
|
80
|
+
associatedRecords: associatedRecords,
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
/** A complete DID-based record URI: record key present, no fragment. */
|
|
84
|
+
const parseRecordUri = (value) => {
|
|
85
|
+
const parsed = parseAtUriString(value);
|
|
86
|
+
if (parsed.success &&
|
|
87
|
+
isDidString(parsed.value.authority) &&
|
|
88
|
+
parsed.value.collection &&
|
|
89
|
+
parsed.value.rkey &&
|
|
90
|
+
!parsed.value.hash) {
|
|
91
|
+
return { uri: value, collection: parsed.value.collection };
|
|
92
|
+
}
|
|
93
|
+
return undefined;
|
|
94
|
+
};
|
|
95
|
+
const isStandardSiteUri = (uri) => {
|
|
96
|
+
const collection = parseRecordUri(uri)?.collection;
|
|
97
|
+
return (collection === site.standard.document.$type ||
|
|
98
|
+
collection === site.standard.publication.$type);
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Reduce the request to one record URI. An explicit `canonicalUri` wins and
|
|
102
|
+
* is never retried with `uris`. Otherwise the legacy `uris` input selects the
|
|
103
|
+
* first Standard.site document, or else the first publication, regardless of
|
|
104
|
+
* array order. No I/O: selection depends only on the supplied URIs.
|
|
105
|
+
*/
|
|
106
|
+
const normalizeCanonicalUri = (params) => {
|
|
107
|
+
if (params.canonicalUri !== undefined) {
|
|
108
|
+
return parseRecordUri(params.canonicalUri)?.uri;
|
|
38
109
|
}
|
|
39
|
-
|
|
110
|
+
const candidates = (params.uris ?? []).flatMap((value) => {
|
|
111
|
+
const parsed = parseRecordUri(value);
|
|
112
|
+
return parsed ? [parsed] : [];
|
|
113
|
+
});
|
|
114
|
+
const preferred = candidates.find((c) => c.collection === site.standard.document.$type) ??
|
|
115
|
+
candidates.find((c) => c.collection === site.standard.publication.$type);
|
|
116
|
+
return preferred?.uri;
|
|
40
117
|
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Persistence policy, not render-time hydration: the canonical record (when
|
|
120
|
+
* available, whatever its collection) plus only the additional collections
|
|
121
|
+
* opted in here, so records baked into a post stay slim. Hydration still holds
|
|
122
|
+
* the full state (e.g. recommendation, subscription and favorite records that
|
|
123
|
+
* back the rendered `likers`/`subscribers` previews); those are deliberately
|
|
124
|
+
* not persisted. An absent entry means no additional collections. Add a
|
|
125
|
+
* collection here only when a post must carry it.
|
|
126
|
+
*/
|
|
127
|
+
const PERSISTED_DEPENDENCY_COLLECTIONS = new Map([
|
|
128
|
+
[site.standard.document.$type, [site.standard.publication.$type]],
|
|
129
|
+
[
|
|
130
|
+
social.grain.gallery.$type,
|
|
131
|
+
[social.grain.gallery.item.$type, social.grain.photo.$type],
|
|
132
|
+
],
|
|
133
|
+
]);
|
|
134
|
+
/**
|
|
135
|
+
* The canonical record, then the hydrated dependencies whose URI collection is
|
|
136
|
+
* opted in by `PERSISTED_DEPENDENCY_COLLECTIONS` for the canonical collection.
|
|
137
|
+
* Refs and associatedRecords are index-aligned, with CIDs taken from
|
|
138
|
+
* hydration; unavailable records are excluded.
|
|
139
|
+
*/
|
|
140
|
+
const collectAssociations = (canonicalUri, records) => {
|
|
52
141
|
const associatedRefs = [];
|
|
53
142
|
const associatedRecords = [];
|
|
54
|
-
|
|
55
|
-
|
|
143
|
+
const canonicalCollection = parseRecordUri(canonicalUri)?.collection;
|
|
144
|
+
const persisted = (canonicalCollection &&
|
|
145
|
+
PERSISTED_DEPENDENCY_COLLECTIONS.get(canonicalCollection)) ||
|
|
146
|
+
[];
|
|
147
|
+
const uris = [
|
|
148
|
+
canonicalUri,
|
|
149
|
+
...[...records.keys()].filter((uri) => uri !== canonicalUri),
|
|
150
|
+
];
|
|
151
|
+
for (const uri of uris) {
|
|
152
|
+
const info = records.get(uri);
|
|
153
|
+
if (!info)
|
|
56
154
|
continue;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
155
|
+
if (uri !== canonicalUri) {
|
|
156
|
+
const collection = parseRecordUri(uri)?.collection;
|
|
157
|
+
if (!collection || !persisted.includes(collection))
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
associatedRefs.push(com.atproto.repo.strongRef.$build({ uri, cid: info.cid }));
|
|
161
|
+
associatedRecords.push(info.record);
|
|
62
162
|
}
|
|
63
|
-
|
|
64
|
-
return {};
|
|
65
|
-
const overlay = ctx.views.externalEmbedFromStandardSiteRecords({
|
|
66
|
-
document,
|
|
67
|
-
publication,
|
|
68
|
-
state: hydration,
|
|
69
|
-
assumedUrl: params.url,
|
|
70
|
-
});
|
|
71
|
-
// The view builder rejected the records (validation failed, or the pair
|
|
72
|
-
// didn't produce the title viewExternal requires). Return nothing — Cardy
|
|
73
|
-
// falls back to its own card render and doesn't write strongRefs to the
|
|
74
|
-
// post.
|
|
75
|
-
if (!overlay)
|
|
76
|
-
return {};
|
|
77
|
-
const view = app.bsky.embed.external.view.$build({
|
|
78
|
-
external: {
|
|
79
|
-
...overlay,
|
|
80
|
-
uri: params.url,
|
|
81
|
-
associatedRefs,
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
return { view, associatedRefs, associatedRecords };
|
|
163
|
+
return { associatedRefs, associatedRecords };
|
|
85
164
|
};
|
|
86
165
|
//# sourceMappingURL=getEmbedExternalView.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getEmbedExternalView.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/embed/getEmbedExternalView.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AtUriString, LexMap } from '@atproto/lex'\nimport type { Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport {\n type SiteStandardDocuments,\n type SiteStandardPublications,\n getSiteStandardRecordsFromHydrationMapsByDocumentUri,\n} from '../../../../hydration/external.js'\nimport type { HydrateCtx, Hydrator } from '../../../../hydration/hydrator.js'\nimport { app, com } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type SkeletonFnInput,\n createPipeline,\n noRules,\n} from '../../../../pipeline.js'\nimport type { Views } from '../../../../views/index.js'\nimport type { ExternalEmbedView, StrongRef } from '../../../../views/types.js'\nimport { resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getEmbedExternalView = createPipeline(\n skeleton,\n hydration,\n noRules,\n presentation,\n )\n server.add(app.bsky.embed.getEmbedExternalView, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ params, auth, req }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({ labelers, viewer })\n const result = await getEmbedExternalView({ ...params, hydrateCtx }, ctx)\n return {\n encoding: 'application/json',\n body: result,\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n },\n })\n}\n\nconst skeleton = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n return { uris: inputs.params.uris as AtUriString[] }\n}\n\nconst hydration = async (\n inputs: HydrationFnInput<Context, Params, Skeleton>,\n) => {\n const { ctx, params, skeleton } = inputs\n return ctx.hydrator.hydrateEmbedExternalViewFromUris(\n skeleton.uris,\n params.hydrateCtx,\n )\n}\n\nconst presentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n): Output => {\n const { hydration } = inputs\n const documents = hydration.siteStandardDocuments\n const publications = hydration.siteStandardPublications\n // Dispatch by record type. Today site.standard is the only kind we know\n // how to render; future record types get their own branch.\n if (\n (documents && documents.size > 0) ||\n (publications && publications.size > 0)\n ) {\n return standardSitePresentation(inputs, documents, publications)\n }\n return {}\n}\n\nconst standardSitePresentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n documents: SiteStandardDocuments | undefined,\n publications: SiteStandardPublications | undefined,\n): Output => {\n const { ctx, params, hydration } = inputs\n\n // Pick the first hydrated doc, then pair it with the publication its\n // `site` field points at (if any). Docs the dataplane auto-resolved a\n // publication for end up matched; unrelated publications fall away.\n const { document, publication } =\n getSiteStandardRecordsFromHydrationMapsByDocumentUri(\n documents,\n publications,\n )\n\n // Emit response refs/records only for the records we actually selected.\n // Anything else (e.g. extra publications the dataplane returned) is\n // intentionally excluded so the strongRefs Cardy writes onto the post\n // match the view we built. Profiles are emitted in the same order as\n // refs (one per slot) so consumers can match by index.\n const associatedRefs: StrongRef[] = []\n const associatedRecords: LexMap[] = []\n for (const slot of [document, publication]) {\n if (!slot) continue\n associatedRefs.push(\n com.atproto.repo.strongRef.$build({\n uri: slot.ref.uri,\n cid: slot.info.cid,\n }),\n )\n associatedRecords.push(slot.info.record as LexMap)\n }\n\n if (!associatedRefs.length) return {}\n\n const overlay = ctx.views.externalEmbedFromStandardSiteRecords({\n document,\n publication,\n state: hydration,\n assumedUrl: params.url,\n })\n // The view builder rejected the records (validation failed, or the pair\n // didn't produce the title viewExternal requires). Return nothing — Cardy\n // falls back to its own card render and doesn't write strongRefs to the\n // post.\n if (!overlay) return {}\n\n const view = app.bsky.embed.external.view.$build({\n external: {\n ...overlay,\n uri: params.url,\n associatedRefs,\n },\n })\n\n return { view, associatedRefs, associatedRecords }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n}\n\ntype Params = app.bsky.embed.getEmbedExternalView.$Params & {\n hydrateCtx: HydrateCtx\n}\n\ntype Skeleton = {\n uris: AtUriString[]\n}\n\ntype Output = {\n view?: ExternalEmbedView\n associatedRefs?: StrongRef[]\n associatedRecords?: LexMap[]\n}\n"]}
|
|
1
|
+
{"version":3,"file":"getEmbedExternalView.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/embed/getEmbedExternalView.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AtUriString,\n type LexMap,\n type TypedLexMap,\n isDidString,\n} from '@atproto/lex'\nimport { parseAtUriString } from '@atproto/syntax'\nimport type { Server } from '@atproto/xrpc-server'\nimport type { ServerConfig } from '../../../../config.js'\nimport type { AppContext } from '../../../../context.js'\nimport type { ExternalRecords } from '../../../../hydration/external.js'\nimport type {\n HydrateCtx,\n HydrationState,\n Hydrator,\n} from '../../../../hydration/hydrator.js'\nimport { app, com, site, social } from '../../../../lexicons/index.js'\nimport {\n type HydrationFnInput,\n type PresentationFnInput,\n type SkeletonFnInput,\n createPipeline,\n noRules,\n} from '../../../../pipeline.js'\nimport { isExternalRecordUrlSafe } from '../../../../util/external/index.js'\nimport {\n getStandardSiteRecordsForUri,\n validateStandardSiteRecordsForUrl,\n} from '../../../../util/external/standard-site.js'\nimport type { Views } from '../../../../views/index.js'\nimport { resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getEmbedExternalView = createPipeline(\n skeleton,\n hydration,\n noRules,\n presentation,\n )\n server.add(app.bsky.embed.getEmbedExternalView, {\n auth: ctx.authVerifier.standardOptional,\n handler: async ({ params, auth, req }) => {\n const viewer = auth.credentials.iss\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({ labelers, viewer })\n const result = await getEmbedExternalView({ ...params, hydrateCtx }, ctx)\n return {\n encoding: 'application/json',\n body: result,\n headers: resHeaders({ labelers: hydrateCtx.labelers }),\n }\n },\n })\n}\n\nconst skeleton = async (\n inputs: SkeletonFnInput<Context, Params>,\n): Promise<Skeleton> => {\n return { canonicalUri: normalizeCanonicalUri(inputs.params) }\n}\n\nconst hydration = async (\n inputs: HydrationFnInput<Context, Params, Skeleton>,\n): Promise<HydrationState> => {\n const { ctx, params, skeleton } = inputs\n if (!skeleton.canonicalUri) return { ctx: params.hydrateCtx }\n return ctx.hydrator.hydrateEmbedExternalViewFromUris(\n [skeleton.canonicalUri],\n params.hydrateCtx,\n )\n}\n\nconst presentation = (\n inputs: PresentationFnInput<Context, Params, Skeleton>,\n): Output => {\n const { ctx, params, skeleton, hydration } = inputs\n const { canonicalUri } = skeleton\n if (!canonicalUri) return {}\n\n if (!hydration.externalRecords?.get(canonicalUri)) return {}\n\n const { associatedRefs, associatedRecords } = collectAssociations(\n canonicalUri,\n hydration.externalRecords,\n )\n\n // Validate before building any view: trust must not depend on whether the\n // records happen to be renderable.\n const standardSite = isStandardSiteUri(canonicalUri)\n const standardSiteRecords = standardSite\n ? getStandardSiteRecordsForUri(canonicalUri, hydration.externalRecords)\n : undefined\n const verified = standardSiteRecords\n ? validateStandardSiteRecordsForUrl(\n standardSiteRecords.document,\n standardSiteRecords.publication,\n params.url,\n )\n : isExternalRecordUrlSafe(params.url, ctx.cfg.externalRecordsSafeDomains)\n\n if (!verified) {\n return {\n unverifiedAssociatedRefs: associatedRefs,\n unverifiedAssociatedRecords: associatedRecords,\n }\n }\n\n const data = ctx.views.externalRecordView(canonicalUri, hydration)\n\n let view: Output['view']\n if (standardSiteRecords) {\n const standardSiteView = ctx.views.externalEmbedFromStandardSiteRecords({\n document: standardSiteRecords.document,\n publication: standardSiteRecords.publication,\n state: hydration,\n assumedUrl: params.url,\n })\n if (standardSiteView) {\n view = app.bsky.embed.external.view.$build({\n external: {\n ...standardSiteView,\n uri: params.url,\n associatedRefs: associatedRefs,\n },\n })\n }\n }\n\n return {\n view,\n data,\n associatedRefs: associatedRefs,\n associatedRecords: associatedRecords,\n }\n}\n\ntype RecordUri = { uri: AtUriString; collection: string }\n\n/** A complete DID-based record URI: record key present, no fragment. */\nconst parseRecordUri = (value: string): RecordUri | undefined => {\n const parsed = parseAtUriString(value)\n if (\n parsed.success &&\n isDidString(parsed.value.authority) &&\n parsed.value.collection &&\n parsed.value.rkey &&\n !parsed.value.hash\n ) {\n return { uri: value as AtUriString, collection: parsed.value.collection }\n }\n return undefined\n}\n\nconst isStandardSiteUri = (uri: AtUriString): boolean => {\n const collection = parseRecordUri(uri)?.collection\n return (\n collection === site.standard.document.$type ||\n collection === site.standard.publication.$type\n )\n}\n\n/**\n * Reduce the request to one record URI. An explicit `canonicalUri` wins and\n * is never retried with `uris`. Otherwise the legacy `uris` input selects the\n * first Standard.site document, or else the first publication, regardless of\n * array order. No I/O: selection depends only on the supplied URIs.\n */\nconst normalizeCanonicalUri = (params: Params): AtUriString | undefined => {\n if (params.canonicalUri !== undefined) {\n return parseRecordUri(params.canonicalUri)?.uri\n }\n const candidates = (params.uris ?? []).flatMap((value) => {\n const parsed = parseRecordUri(value)\n return parsed ? [parsed] : []\n })\n const preferred =\n candidates.find((c) => c.collection === site.standard.document.$type) ??\n candidates.find((c) => c.collection === site.standard.publication.$type)\n return preferred?.uri\n}\n\n/**\n * Persistence policy, not render-time hydration: the canonical record (when\n * available, whatever its collection) plus only the additional collections\n * opted in here, so records baked into a post stay slim. Hydration still holds\n * the full state (e.g. recommendation, subscription and favorite records that\n * back the rendered `likers`/`subscribers` previews); those are deliberately\n * not persisted. An absent entry means no additional collections. Add a\n * collection here only when a post must carry it.\n */\nconst PERSISTED_DEPENDENCY_COLLECTIONS: ReadonlyMap<string, readonly string[]> =\n new Map<string, readonly string[]>([\n [site.standard.document.$type, [site.standard.publication.$type]],\n [\n social.grain.gallery.$type,\n [social.grain.gallery.item.$type, social.grain.photo.$type],\n ],\n ])\n\n/**\n * The canonical record, then the hydrated dependencies whose URI collection is\n * opted in by `PERSISTED_DEPENDENCY_COLLECTIONS` for the canonical collection.\n * Refs and associatedRecords are index-aligned, with CIDs taken from\n * hydration; unavailable records are excluded.\n */\nconst collectAssociations = (\n canonicalUri: AtUriString,\n records: ExternalRecords,\n): { associatedRefs: StrongRef[]; associatedRecords: LexMap[] } => {\n const associatedRefs: StrongRef[] = []\n const associatedRecords: LexMap[] = []\n const canonicalCollection = parseRecordUri(canonicalUri)?.collection\n const persisted =\n (canonicalCollection &&\n PERSISTED_DEPENDENCY_COLLECTIONS.get(canonicalCollection)) ||\n []\n const uris = [\n canonicalUri,\n ...[...records.keys()].filter((uri) => uri !== canonicalUri),\n ]\n for (const uri of uris) {\n const info = records.get(uri)\n if (!info) continue\n if (uri !== canonicalUri) {\n const collection = parseRecordUri(uri)?.collection\n if (!collection || !persisted.includes(collection)) continue\n }\n associatedRefs.push(\n com.atproto.repo.strongRef.$build({ uri, cid: info.cid }),\n )\n associatedRecords.push(info.record as TypedLexMap)\n }\n return { associatedRefs, associatedRecords }\n}\n\ntype StrongRef = com.atproto.repo.strongRef.Main\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n cfg: Pick<ServerConfig, 'externalRecordsSafeDomains'>\n}\n\ntype Params = app.bsky.embed.getEmbedExternalView.$Params & {\n hydrateCtx: HydrateCtx\n}\n\ntype Skeleton = {\n canonicalUri?: AtUriString\n}\n\ntype Output = app.bsky.embed.getEmbedExternalView.$OutputBody\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getAuthorFeed.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/feed/getAuthorFeed.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AACtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAA;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAQ,MAAM,+BAA+B,CAAA;AACnE,OAAO,EACL,KAAK,UAAU,EAEf,KAAK,QAAQ,EAEd,MAAM,mCAAmC,CAAA;AAE1C,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AAInD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAGvD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QA2CvD;AAUD,eAAO,MAAM,QAAQ,WAAkB;IACrC,GAAG,EAAE,OAAO,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf,KAAG,OAAO,CAAC,QAAQ,CA2DnB,CAAA;
|
|
1
|
+
{"version":3,"file":"getAuthorFeed.d.ts","sourceRoot":"","sources":["../../../../../src/api/app/bsky/feed/getAuthorFeed.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAA;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AACtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAA;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAQ,MAAM,+BAA+B,CAAA;AACnE,OAAO,EACL,KAAK,UAAU,EAEf,KAAK,QAAQ,EAEd,MAAM,mCAAmC,CAAA;AAE1C,OAAO,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AAInD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAGvD,MAAM,CAAC,OAAO,WAAW,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,QA2CvD;AAUD,eAAO,MAAM,QAAQ,WAAkB;IACrC,GAAG,EAAE,OAAO,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf,KAAG,OAAO,CAAC,QAAQ,CA2DnB,CAAA;AAuFD,KAAK,OAAO,GAAG;IACb,QAAQ,EAAE,QAAQ,CAAA;IAClB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,eAAe,CAAA;CAC3B,CAAA;AAED,KAAK,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,GAAG;IAClD,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AAED,KAAK,QAAQ,GAAG;IACd,KAAK,EAAE,KAAK,CAAA;IACZ,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACrD,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA"}
|
|
@@ -113,11 +113,13 @@ const hydration = async (inputs) => {
|
|
|
113
113
|
const noBlocksOrMutedReposts = (inputs) => {
|
|
114
114
|
const { ctx, skeleton, hydration } = inputs;
|
|
115
115
|
const relationship = hydration.profileViewers?.get(skeleton.actor.did);
|
|
116
|
-
if (
|
|
116
|
+
if (!hydration.ctx?.skipViewerBlocks &&
|
|
117
|
+
relationship &&
|
|
117
118
|
(relationship.blocking || ctx.views.blockingByList(relationship, hydration))) {
|
|
118
119
|
throw new InvalidRequestError(`Requester has blocked actor: ${skeleton.actor.did}`, 'BlockedActor');
|
|
119
120
|
}
|
|
120
|
-
if (
|
|
121
|
+
if (!hydration.ctx?.skipViewerBlocks &&
|
|
122
|
+
relationship &&
|
|
121
123
|
(relationship.blockedBy || ctx.views.blockedByList(relationship, hydration))) {
|
|
122
124
|
throw new InvalidRequestError(`Requester is blocked by actor: ${skeleton.actor.did}`, 'BlockedByActor');
|
|
123
125
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getAuthorFeed.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/feed/getAuthorFeed.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined } from '@atproto/common'\nimport type { AtUriString } from '@atproto/lex'\nimport { InvalidRequestError, type Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport type { DataPlaneClient } from '../../../../data-plane/index.js'\nimport type { Actor } from '../../../../hydration/actor.js'\nimport type { FeedItem, Post } from '../../../../hydration/feed.js'\nimport {\n type HydrateCtx,\n type HydrationState,\n type Hydrator,\n mergeStates,\n} from '../../../../hydration/hydrator.js'\nimport { parseString } from '../../../../hydration/util.js'\nimport { app } from '../../../../lexicons/index.js'\nimport { createPipeline } from '../../../../pipeline.js'\nimport { FeedType } from '../../../../proto/bsky_pb.js'\nimport { safePinnedPost, uriToDid } from '../../../../util/uris.js'\nimport type { Views } from '../../../../views/index.js'\nimport { clearlyBadCursor, fillPage, resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getAuthorFeed = createPipeline(\n skeleton,\n hydration,\n noBlocksOrMutedReposts,\n presentation,\n )\n server.add(app.bsky.feed.getAuthorFeed, {\n auth: ctx.authVerifier.optionalStandardOrRole,\n handler: async ({ params, auth, req }) => {\n const { viewer, includeTakedowns, skipViewerBlocks } =\n ctx.authVerifier.parseCreds(auth)\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n labelers,\n viewer,\n includeTakedowns,\n skipViewerBlocks,\n features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({ viewer, req }),\n ),\n })\n\n const result = await fillPage({\n cursor: params.cursor,\n limit: params.limit,\n fetch: ({ cursor, limit }) =>\n getAuthorFeed({ ...params, cursor, limit, hydrateCtx }, ctx),\n items: (r) => r.feed,\n })\n\n const repoRev = await ctx.hydrator.actor.getRepoRevSafe(viewer)\n\n return {\n encoding: 'application/json',\n body: result,\n headers: resHeaders({\n repoRev,\n labelers: hydrateCtx.labelers,\n }),\n }\n },\n })\n}\n\nconst FILTER_TO_FEED_TYPE = {\n posts_with_replies: undefined, // default: all posts, replies, and reposts\n posts_no_replies: FeedType.POSTS_NO_REPLIES,\n posts_with_media: FeedType.POSTS_WITH_MEDIA,\n posts_and_author_threads: FeedType.POSTS_AND_AUTHOR_THREADS,\n posts_with_video: FeedType.POSTS_WITH_VIDEO,\n}\n\nexport const skeleton = async (inputs: {\n ctx: Context\n params: Params\n}): Promise<Skeleton> => {\n const { ctx, params } = inputs\n const [did] = await ctx.hydrator.actor.getDids([params.actor])\n if (!did) {\n throw new InvalidRequestError('Profile not found')\n }\n const actors = await ctx.hydrator.actor.getActors([did], {\n includeTakedowns: params.hydrateCtx.includeTakedowns,\n skipCacheForDids: params.hydrateCtx.skipCacheForViewer,\n })\n const actor = actors.get(did)\n if (!actor) {\n throw new InvalidRequestError('Profile not found')\n }\n if (clearlyBadCursor(params.cursor)) {\n return { actor, filter: params.filter, items: [] }\n }\n\n const pinnedPost = safePinnedPost(actor.profile?.pinnedPost)\n const isFirstPageRequest = !params.cursor\n const shouldInsertPinnedPost =\n isFirstPageRequest &&\n params.includePins &&\n pinnedPost &&\n uriToDid(pinnedPost.uri) === actor.did\n\n const res = await ctx.dataplane.getAuthorFeed({\n actorDid: did,\n limit: params.limit,\n cursor: params.cursor,\n feedType: FILTER_TO_FEED_TYPE[params.filter],\n })\n\n let items: FeedItem[] = res.items.map((item) => ({\n post: { uri: item.uri as AtUriString, cid: item.cid || undefined },\n repost: item.repost\n ? { uri: item.repost as AtUriString, cid: item.repostCid || undefined }\n : undefined,\n }))\n\n if (shouldInsertPinnedPost && pinnedPost) {\n const pinnedItem = {\n post: {\n uri: pinnedPost.uri,\n cid: pinnedPost.cid,\n },\n authorPinned: true,\n }\n\n items = items.filter((item) => item.post.uri !== pinnedItem.post.uri)\n items.unshift(pinnedItem)\n }\n\n return {\n actor,\n filter: params.filter,\n items,\n cursor: parseString(res.cursor),\n }\n}\n\nconst hydration = async (inputs: {\n ctx: Context\n params: Params\n skeleton: Skeleton\n}): Promise<HydrationState> => {\n const { ctx, params, skeleton } = inputs\n const [feedPostState, profileViewerState] = await Promise.all([\n ctx.hydrator.hydrateFeedItems(skeleton.items, params.hydrateCtx, {\n knownLikers:\n !!params.hydrateCtx.viewer &&\n params.hydrateCtx.features.checkGate(\n params.hydrateCtx.features.Gate.KnownLikersFeedEnable,\n ),\n }),\n ctx.hydrator.hydrateProfileViewers([skeleton.actor.did], params.hydrateCtx),\n ])\n return mergeStates(feedPostState, profileViewerState)\n}\n\nconst noBlocksOrMutedReposts = (inputs: {\n ctx: Context\n skeleton: Skeleton\n hydration: HydrationState\n}): Skeleton => {\n const { ctx, skeleton, hydration } = inputs\n const relationship = hydration.profileViewers?.get(skeleton.actor.did)\n if (\n relationship &&\n (relationship.blocking || ctx.views.blockingByList(relationship, hydration))\n ) {\n throw new InvalidRequestError(\n `Requester has blocked actor: ${skeleton.actor.did}`,\n 'BlockedActor',\n )\n }\n if (\n relationship &&\n (relationship.blockedBy || ctx.views.blockedByList(relationship, hydration))\n ) {\n throw new InvalidRequestError(\n `Requester is blocked by actor: ${skeleton.actor.did}`,\n 'BlockedByActor',\n )\n }\n\n const checkBlocksAndMutes = (item: FeedItem) => {\n const bam = ctx.views.feedItemBlocksAndMutes(item, hydration)\n return (\n !bam.authorBlocked &&\n !bam.originatorBlocked &&\n (!bam.authorMuted || bam.originatorMuted) // repost of muted content\n )\n }\n\n if (skeleton.filter === 'posts_and_author_threads') {\n // ensure replies are only included if the feed contains all\n // replies up to the thread root (i.e. a complete self-thread.)\n const selfThread = new SelfThreadTracker(skeleton.items, hydration)\n skeleton.items = skeleton.items.filter((item) => {\n return (\n checkBlocksAndMutes(item) &&\n (item.repost || item.authorPinned || selfThread.ok(item.post.uri))\n )\n })\n } else {\n skeleton.items = skeleton.items.filter(checkBlocksAndMutes)\n }\n\n return skeleton\n}\n\nconst presentation = (inputs: {\n ctx: Context\n skeleton: Skeleton\n hydration: HydrationState\n}) => {\n const { ctx, skeleton, hydration } = inputs\n const feed = mapDefined(skeleton.items, (item) =>\n ctx.views.feedViewPost(item, hydration),\n )\n return { feed, cursor: skeleton.cursor }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n dataplane: DataPlaneClient\n}\n\ntype Params = app.bsky.feed.getAuthorFeed.$Params & {\n hydrateCtx: HydrateCtx\n}\n\ntype Skeleton = {\n actor: Actor\n items: FeedItem[]\n filter: app.bsky.feed.getAuthorFeed.$Params['filter']\n cursor?: string\n}\n\nclass SelfThreadTracker {\n feedUris = new Set<AtUriString>()\n cache = new Map<AtUriString, boolean>()\n\n constructor(\n items: FeedItem[],\n private hydration: HydrationState,\n ) {\n items.forEach((item) => {\n if (!item.repost) {\n this.feedUris.add(item.post.uri)\n }\n })\n }\n\n ok(uri: AtUriString, loop = new Set<AtUriString>()) {\n // if we've already checked this uri, pull from the cache\n if (this.cache.has(uri)) {\n return this.cache.get(uri) ?? false\n }\n // loop detection\n if (loop.has(uri)) {\n this.cache.set(uri, false)\n return false\n } else {\n loop.add(uri)\n }\n // cache through the result\n const result = this._ok(uri, loop)\n this.cache.set(uri, result)\n return result\n }\n\n private _ok(uri: AtUriString, loop: Set<AtUriString>): boolean {\n // must be in the feed to be in a self-thread\n if (!this.feedUris.has(uri)) {\n return false\n }\n // must be hydratable to be part of self-thread\n const post = this.hydration.posts?.get(uri)\n if (!post) {\n return false\n }\n // root posts (no parent) are trivial case of self-thread\n const parentUri = getParentUri(post)\n if (parentUri === null) {\n return true\n }\n // recurse w/ cache: this post is in a self-thread if its parent is.\n return this.ok(parentUri, loop)\n }\n}\n\nfunction getParentUri(post: Post) {\n return post.record.reply?.parent.uri ?? null\n}\n"]}
|
|
1
|
+
{"version":3,"file":"getAuthorFeed.js","sourceRoot":"","sources":["../../../../../src/api/app/bsky/feed/getAuthorFeed.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapDefined } from '@atproto/common'\nimport type { AtUriString } from '@atproto/lex'\nimport { InvalidRequestError, type Server } from '@atproto/xrpc-server'\nimport type { AppContext } from '../../../../context.js'\nimport type { DataPlaneClient } from '../../../../data-plane/index.js'\nimport type { Actor } from '../../../../hydration/actor.js'\nimport type { FeedItem, Post } from '../../../../hydration/feed.js'\nimport {\n type HydrateCtx,\n type HydrationState,\n type Hydrator,\n mergeStates,\n} from '../../../../hydration/hydrator.js'\nimport { parseString } from '../../../../hydration/util.js'\nimport { app } from '../../../../lexicons/index.js'\nimport { createPipeline } from '../../../../pipeline.js'\nimport { FeedType } from '../../../../proto/bsky_pb.js'\nimport { safePinnedPost, uriToDid } from '../../../../util/uris.js'\nimport type { Views } from '../../../../views/index.js'\nimport { clearlyBadCursor, fillPage, resHeaders } from '../../../util.js'\n\nexport default function (server: Server, ctx: AppContext) {\n const getAuthorFeed = createPipeline(\n skeleton,\n hydration,\n noBlocksOrMutedReposts,\n presentation,\n )\n server.add(app.bsky.feed.getAuthorFeed, {\n auth: ctx.authVerifier.optionalStandardOrRole,\n handler: async ({ params, auth, req }) => {\n const { viewer, includeTakedowns, skipViewerBlocks } =\n ctx.authVerifier.parseCreds(auth)\n const labelers = ctx.reqLabelers(req)\n const hydrateCtx = await ctx.hydrator.createContext({\n labelers,\n viewer,\n includeTakedowns,\n skipViewerBlocks,\n features: ctx.featureGatesClient.scope(\n ctx.featureGatesClient.parseUserContextFromHandler({ viewer, req }),\n ),\n })\n\n const result = await fillPage({\n cursor: params.cursor,\n limit: params.limit,\n fetch: ({ cursor, limit }) =>\n getAuthorFeed({ ...params, cursor, limit, hydrateCtx }, ctx),\n items: (r) => r.feed,\n })\n\n const repoRev = await ctx.hydrator.actor.getRepoRevSafe(viewer)\n\n return {\n encoding: 'application/json',\n body: result,\n headers: resHeaders({\n repoRev,\n labelers: hydrateCtx.labelers,\n }),\n }\n },\n })\n}\n\nconst FILTER_TO_FEED_TYPE = {\n posts_with_replies: undefined, // default: all posts, replies, and reposts\n posts_no_replies: FeedType.POSTS_NO_REPLIES,\n posts_with_media: FeedType.POSTS_WITH_MEDIA,\n posts_and_author_threads: FeedType.POSTS_AND_AUTHOR_THREADS,\n posts_with_video: FeedType.POSTS_WITH_VIDEO,\n}\n\nexport const skeleton = async (inputs: {\n ctx: Context\n params: Params\n}): Promise<Skeleton> => {\n const { ctx, params } = inputs\n const [did] = await ctx.hydrator.actor.getDids([params.actor])\n if (!did) {\n throw new InvalidRequestError('Profile not found')\n }\n const actors = await ctx.hydrator.actor.getActors([did], {\n includeTakedowns: params.hydrateCtx.includeTakedowns,\n skipCacheForDids: params.hydrateCtx.skipCacheForViewer,\n })\n const actor = actors.get(did)\n if (!actor) {\n throw new InvalidRequestError('Profile not found')\n }\n if (clearlyBadCursor(params.cursor)) {\n return { actor, filter: params.filter, items: [] }\n }\n\n const pinnedPost = safePinnedPost(actor.profile?.pinnedPost)\n const isFirstPageRequest = !params.cursor\n const shouldInsertPinnedPost =\n isFirstPageRequest &&\n params.includePins &&\n pinnedPost &&\n uriToDid(pinnedPost.uri) === actor.did\n\n const res = await ctx.dataplane.getAuthorFeed({\n actorDid: did,\n limit: params.limit,\n cursor: params.cursor,\n feedType: FILTER_TO_FEED_TYPE[params.filter],\n })\n\n let items: FeedItem[] = res.items.map((item) => ({\n post: { uri: item.uri as AtUriString, cid: item.cid || undefined },\n repost: item.repost\n ? { uri: item.repost as AtUriString, cid: item.repostCid || undefined }\n : undefined,\n }))\n\n if (shouldInsertPinnedPost && pinnedPost) {\n const pinnedItem = {\n post: {\n uri: pinnedPost.uri,\n cid: pinnedPost.cid,\n },\n authorPinned: true,\n }\n\n items = items.filter((item) => item.post.uri !== pinnedItem.post.uri)\n items.unshift(pinnedItem)\n }\n\n return {\n actor,\n filter: params.filter,\n items,\n cursor: parseString(res.cursor),\n }\n}\n\nconst hydration = async (inputs: {\n ctx: Context\n params: Params\n skeleton: Skeleton\n}): Promise<HydrationState> => {\n const { ctx, params, skeleton } = inputs\n const [feedPostState, profileViewerState] = await Promise.all([\n ctx.hydrator.hydrateFeedItems(skeleton.items, params.hydrateCtx, {\n knownLikers:\n !!params.hydrateCtx.viewer &&\n params.hydrateCtx.features.checkGate(\n params.hydrateCtx.features.Gate.KnownLikersFeedEnable,\n ),\n }),\n ctx.hydrator.hydrateProfileViewers([skeleton.actor.did], params.hydrateCtx),\n ])\n return mergeStates(feedPostState, profileViewerState)\n}\n\nconst noBlocksOrMutedReposts = (inputs: {\n ctx: Context\n skeleton: Skeleton\n hydration: HydrationState\n}): Skeleton => {\n const { ctx, skeleton, hydration } = inputs\n const relationship = hydration.profileViewers?.get(skeleton.actor.did)\n if (\n !hydration.ctx?.skipViewerBlocks &&\n relationship &&\n (relationship.blocking || ctx.views.blockingByList(relationship, hydration))\n ) {\n throw new InvalidRequestError(\n `Requester has blocked actor: ${skeleton.actor.did}`,\n 'BlockedActor',\n )\n }\n if (\n !hydration.ctx?.skipViewerBlocks &&\n relationship &&\n (relationship.blockedBy || ctx.views.blockedByList(relationship, hydration))\n ) {\n throw new InvalidRequestError(\n `Requester is blocked by actor: ${skeleton.actor.did}`,\n 'BlockedByActor',\n )\n }\n\n const checkBlocksAndMutes = (item: FeedItem) => {\n const bam = ctx.views.feedItemBlocksAndMutes(item, hydration)\n return (\n !bam.authorBlocked &&\n !bam.originatorBlocked &&\n (!bam.authorMuted || bam.originatorMuted) // repost of muted content\n )\n }\n\n if (skeleton.filter === 'posts_and_author_threads') {\n // ensure replies are only included if the feed contains all\n // replies up to the thread root (i.e. a complete self-thread.)\n const selfThread = new SelfThreadTracker(skeleton.items, hydration)\n skeleton.items = skeleton.items.filter((item) => {\n return (\n checkBlocksAndMutes(item) &&\n (item.repost || item.authorPinned || selfThread.ok(item.post.uri))\n )\n })\n } else {\n skeleton.items = skeleton.items.filter(checkBlocksAndMutes)\n }\n\n return skeleton\n}\n\nconst presentation = (inputs: {\n ctx: Context\n skeleton: Skeleton\n hydration: HydrationState\n}) => {\n const { ctx, skeleton, hydration } = inputs\n const feed = mapDefined(skeleton.items, (item) =>\n ctx.views.feedViewPost(item, hydration),\n )\n return { feed, cursor: skeleton.cursor }\n}\n\ntype Context = {\n hydrator: Hydrator\n views: Views\n dataplane: DataPlaneClient\n}\n\ntype Params = app.bsky.feed.getAuthorFeed.$Params & {\n hydrateCtx: HydrateCtx\n}\n\ntype Skeleton = {\n actor: Actor\n items: FeedItem[]\n filter: app.bsky.feed.getAuthorFeed.$Params['filter']\n cursor?: string\n}\n\nclass SelfThreadTracker {\n feedUris = new Set<AtUriString>()\n cache = new Map<AtUriString, boolean>()\n\n constructor(\n items: FeedItem[],\n private hydration: HydrationState,\n ) {\n items.forEach((item) => {\n if (!item.repost) {\n this.feedUris.add(item.post.uri)\n }\n })\n }\n\n ok(uri: AtUriString, loop = new Set<AtUriString>()) {\n // if we've already checked this uri, pull from the cache\n if (this.cache.has(uri)) {\n return this.cache.get(uri) ?? false\n }\n // loop detection\n if (loop.has(uri)) {\n this.cache.set(uri, false)\n return false\n } else {\n loop.add(uri)\n }\n // cache through the result\n const result = this._ok(uri, loop)\n this.cache.set(uri, result)\n return result\n }\n\n private _ok(uri: AtUriString, loop: Set<AtUriString>): boolean {\n // must be in the feed to be in a self-thread\n if (!this.feedUris.has(uri)) {\n return false\n }\n // must be hydratable to be part of self-thread\n const post = this.hydration.posts?.get(uri)\n if (!post) {\n return false\n }\n // root posts (no parent) are trivial case of self-thread\n const parentUri = getParentUri(post)\n if (parentUri === null) {\n return true\n }\n // recurse w/ cache: this post is in a self-thread if its parent is.\n return this.ok(parentUri, loop)\n }\n}\n\nfunction getParentUri(post: Post) {\n return post.record.reply?.parent.uri ?? null\n}\n"]}
|