@atproto/bsky 0.0.251 → 0.0.253
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 +35 -0
- package/dist/api/age-assurance/const.js +19 -19
- package/dist/api/age-assurance/const.js.map +1 -1
- package/dist/kws.d.ts +8 -0
- package/dist/kws.d.ts.map +1 -1
- package/dist/kws.js +53 -4
- package/dist/kws.js.map +1 -1
- package/package.json +28 -23
- package/bin/migration-create.ts +0 -46
- package/buf.gen.yaml +0 -12
- package/proto/bsky.proto +0 -1907
- package/proto/courier.proto +0 -84
- package/proto/rolodex.proto +0 -116
- package/src/api/age-assurance/const.ts +0 -203
- package/src/api/age-assurance/index.ts +0 -34
- package/src/api/age-assurance/kws/age-verified.test.ts +0 -98
- package/src/api/age-assurance/kws/age-verified.ts +0 -81
- package/src/api/age-assurance/kws/const.ts +0 -33
- package/src/api/age-assurance/kws/external-payload.test.ts +0 -72
- package/src/api/age-assurance/kws/external-payload.ts +0 -149
- package/src/api/age-assurance/redirects/kws-age-verified.ts +0 -107
- package/src/api/age-assurance/stash.ts +0 -23
- package/src/api/age-assurance/types.ts +0 -10
- package/src/api/age-assurance/util.ts +0 -68
- package/src/api/age-assurance/webhooks/kws-age-verified.ts +0 -75
- package/src/api/app/bsky/actor/getProfile.ts +0 -106
- package/src/api/app/bsky/actor/getProfiles.ts +0 -99
- package/src/api/app/bsky/actor/getSuggestions.ts +0 -163
- package/src/api/app/bsky/actor/searchActors.ts +0 -171
- package/src/api/app/bsky/actor/searchActorsTypeahead.ts +0 -164
- package/src/api/app/bsky/ageassurance/begin.ts +0 -175
- package/src/api/app/bsky/ageassurance/getConfig.ts +0 -16
- package/src/api/app/bsky/ageassurance/getState.ts +0 -58
- package/src/api/app/bsky/bookmark/createBookmark.ts +0 -39
- package/src/api/app/bsky/bookmark/deleteBookmark.ts +0 -32
- package/src/api/app/bsky/bookmark/getBookmarks.ts +0 -97
- package/src/api/app/bsky/bookmark/util.ts +0 -13
- package/src/api/app/bsky/contact/dismissMatch.ts +0 -26
- package/src/api/app/bsky/contact/getMatches.ts +0 -111
- package/src/api/app/bsky/contact/getSyncStatus.ts +0 -38
- package/src/api/app/bsky/contact/importContacts.ts +0 -119
- package/src/api/app/bsky/contact/removeData.ts +0 -25
- package/src/api/app/bsky/contact/sendNotification.ts +0 -33
- package/src/api/app/bsky/contact/startPhoneVerification.ts +0 -26
- package/src/api/app/bsky/contact/util.ts +0 -92
- package/src/api/app/bsky/contact/verifyPhone.ts +0 -29
- package/src/api/app/bsky/draft/createDraft.ts +0 -45
- package/src/api/app/bsky/draft/deleteDraft.ts +0 -20
- package/src/api/app/bsky/draft/getDrafts.ts +0 -44
- package/src/api/app/bsky/draft/updateDraft.ts +0 -26
- package/src/api/app/bsky/embed/getEmbedExternalView.ts +0 -154
- package/src/api/app/bsky/feed/getActorFeeds.ts +0 -101
- package/src/api/app/bsky/feed/getActorLikes.ts +0 -128
- package/src/api/app/bsky/feed/getAuthorFeed.ts +0 -279
- package/src/api/app/bsky/feed/getFeed.ts +0 -282
- package/src/api/app/bsky/feed/getFeedGenerator.ts +0 -68
- package/src/api/app/bsky/feed/getFeedGenerators.ts +0 -86
- package/src/api/app/bsky/feed/getLikes.ts +0 -151
- package/src/api/app/bsky/feed/getListFeed.ts +0 -147
- package/src/api/app/bsky/feed/getPostThread.ts +0 -156
- package/src/api/app/bsky/feed/getPosts.ts +0 -100
- package/src/api/app/bsky/feed/getQuotes.ts +0 -122
- package/src/api/app/bsky/feed/getRepostedBy.ts +0 -121
- package/src/api/app/bsky/feed/getSuggestedFeeds.ts +0 -39
- package/src/api/app/bsky/feed/getTimeline.ts +0 -127
- package/src/api/app/bsky/feed/searchPosts.ts +0 -274
- package/src/api/app/bsky/feed/searchPostsV2.ts +0 -243
- package/src/api/app/bsky/graph/getActorStarterPacks.ts +0 -103
- package/src/api/app/bsky/graph/getBlocks.ts +0 -94
- package/src/api/app/bsky/graph/getFollowers.ts +0 -153
- package/src/api/app/bsky/graph/getFollows.ts +0 -151
- package/src/api/app/bsky/graph/getKnownFollowers.ts +0 -123
- package/src/api/app/bsky/graph/getList.ts +0 -152
- package/src/api/app/bsky/graph/getListBlocks.ts +0 -87
- package/src/api/app/bsky/graph/getListMutes.ts +0 -87
- package/src/api/app/bsky/graph/getLists.ts +0 -125
- package/src/api/app/bsky/graph/getListsWithMembership.ts +0 -146
- package/src/api/app/bsky/graph/getMutes.ts +0 -87
- package/src/api/app/bsky/graph/getRelationships.ts +0 -58
- package/src/api/app/bsky/graph/getStarterPack.ts +0 -82
- package/src/api/app/bsky/graph/getStarterPacks.ts +0 -86
- package/src/api/app/bsky/graph/getStarterPacksWithMembership.ts +0 -136
- package/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts +0 -171
- package/src/api/app/bsky/graph/muteActor.ts +0 -24
- package/src/api/app/bsky/graph/muteActorList.ts +0 -19
- package/src/api/app/bsky/graph/muteThread.ts +0 -19
- package/src/api/app/bsky/graph/searchStarterPacks.ts +0 -169
- package/src/api/app/bsky/graph/unmuteActor.ts +0 -21
- package/src/api/app/bsky/graph/unmuteActorList.ts +0 -19
- package/src/api/app/bsky/graph/unmuteThread.ts +0 -19
- package/src/api/app/bsky/labeler/getServices.ts +0 -41
- package/src/api/app/bsky/notification/getPreferences.ts +0 -49
- package/src/api/app/bsky/notification/getUnreadCount.ts +0 -83
- package/src/api/app/bsky/notification/listActivitySubscriptions.ts +0 -116
- package/src/api/app/bsky/notification/listNotifications.ts +0 -272
- package/src/api/app/bsky/notification/putActivitySubscription.ts +0 -69
- package/src/api/app/bsky/notification/putPreferences.ts +0 -17
- package/src/api/app/bsky/notification/putPreferencesV2.ts +0 -64
- package/src/api/app/bsky/notification/registerPush.ts +0 -40
- package/src/api/app/bsky/notification/unregisterPush.ts +0 -39
- package/src/api/app/bsky/notification/updateSeen.ts +0 -52
- package/src/api/app/bsky/notification/util.ts +0 -134
- package/src/api/app/bsky/unspecced/getAgeAssuranceState.ts +0 -48
- package/src/api/app/bsky/unspecced/getConfig.ts +0 -20
- package/src/api/app/bsky/unspecced/getOnboardingSuggestedStarterPacks.ts +0 -162
- package/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +0 -91
- package/src/api/app/bsky/unspecced/getPostThreadOtherV2.ts +0 -126
- package/src/api/app/bsky/unspecced/getPostThreadV2.ts +0 -148
- package/src/api/app/bsky/unspecced/getSuggestedFeeds.ts +0 -100
- package/src/api/app/bsky/unspecced/getSuggestedOnboardingUsers.ts +0 -143
- package/src/api/app/bsky/unspecced/getSuggestedStarterPacks.ts +0 -165
- package/src/api/app/bsky/unspecced/getSuggestedUsers.ts +0 -183
- package/src/api/app/bsky/unspecced/getSuggestedUsersForDiscover.ts +0 -175
- package/src/api/app/bsky/unspecced/getSuggestedUsersForExplore.ts +0 -178
- package/src/api/app/bsky/unspecced/getSuggestedUsersForSeeMore.ts +0 -178
- package/src/api/app/bsky/unspecced/getTaggedSuggestions.ts +0 -27
- package/src/api/app/bsky/unspecced/getTrendingTopics.ts +0 -96
- package/src/api/app/bsky/unspecced/getTrends.ts +0 -162
- package/src/api/app/bsky/unspecced/initAgeAssurance.ts +0 -150
- package/src/api/blob-dispatcher.ts +0 -41
- package/src/api/blob-resolver.ts +0 -401
- package/src/api/com/atproto/admin/getAccountInfos.ts +0 -49
- package/src/api/com/atproto/admin/getSubjectStatus.ts +0 -79
- package/src/api/com/atproto/admin/updateSubjectStatus.ts +0 -80
- package/src/api/com/atproto/identity/resolveHandle.ts +0 -19
- package/src/api/com/atproto/label/queryLabels.ts +0 -42
- package/src/api/com/atproto/repo/getRecord.ts +0 -44
- package/src/api/com/atproto/temp/fetchLabels.ts +0 -9
- package/src/api/external.ts +0 -15
- package/src/api/health.ts +0 -47
- package/src/api/index.ts +0 -216
- package/src/api/internal/bsky/actor/getProfiles.ts +0 -87
- package/src/api/kws/api.ts +0 -113
- package/src/api/kws/index.ts +0 -29
- package/src/api/kws/types.ts +0 -78
- package/src/api/kws/util.test.ts +0 -50
- package/src/api/kws/util.ts +0 -109
- package/src/api/kws/webhook.ts +0 -134
- package/src/api/sitemap.ts +0 -76
- package/src/api/util.ts +0 -45
- package/src/api/well-known.ts +0 -44
- package/src/auth-verifier.ts +0 -522
- package/src/bsync.ts +0 -41
- package/src/cache/read-through.ts +0 -157
- package/src/config.ts +0 -719
- package/src/context.ts +0 -143
- package/src/courier.ts +0 -41
- package/src/data-plane/client/hosts.ts +0 -103
- package/src/data-plane/client/index.ts +0 -125
- package/src/data-plane/client/util.test.ts +0 -29
- package/src/data-plane/client/util.ts +0 -74
- package/src/data-plane/index.ts +0 -2
- package/src/data-plane/server/background.ts +0 -66
- package/src/data-plane/server/bsync-subscription.ts +0 -590
- package/src/data-plane/server/db/database-schema.ts +0 -90
- package/src/data-plane/server/db/db.ts +0 -204
- package/src/data-plane/server/db/index.ts +0 -2
- package/src/data-plane/server/db/migrations/20230309T045948368Z-init.ts +0 -305
- package/src/data-plane/server/db/migrations/20230408T152211201Z-notification-init.ts +0 -25
- package/src/data-plane/server/db/migrations/20230417T210628672Z-moderation-init.ts +0 -127
- package/src/data-plane/server/db/migrations/20230420T211446071Z-did-cache.ts +0 -14
- package/src/data-plane/server/db/migrations/20230427T194702079Z-notif-record-index.ts +0 -14
- package/src/data-plane/server/db/migrations/20230605T144730094Z-post-profile-aggs.ts +0 -23
- package/src/data-plane/server/db/migrations/20230607T211442112Z-feed-generator-init.ts +0 -34
- package/src/data-plane/server/db/migrations/20230608T155101190Z-algo-whats-hot-view.ts +0 -85
- package/src/data-plane/server/db/migrations/20230608T201813132Z-mute-lists.ts +0 -78
- package/src/data-plane/server/db/migrations/20230608T205147239Z-mutes.ts +0 -15
- package/src/data-plane/server/db/migrations/20230609T153623961Z-blocks.ts +0 -33
- package/src/data-plane/server/db/migrations/20230609T232122649Z-actor-deletion-indexes.ts +0 -27
- package/src/data-plane/server/db/migrations/20230610T203555962Z-suggested-follows.ts +0 -13
- package/src/data-plane/server/db/migrations/20230611T215300060Z-actor-state.ts +0 -13
- package/src/data-plane/server/db/migrations/20230620T161134972Z-post-langs.ts +0 -9
- package/src/data-plane/server/db/migrations/20230627T212437895Z-optional-handle.ts +0 -15
- package/src/data-plane/server/db/migrations/20230629T220835893Z-remove-post-hierarchy.ts +0 -32
- package/src/data-plane/server/db/migrations/20230703T045536691Z-feed-and-label-indices.ts +0 -31
- package/src/data-plane/server/db/migrations/20230720T164800037Z-posts-cursor-idx.ts +0 -19
- package/src/data-plane/server/db/migrations/20230807T035309811Z-feed-item-delete-invite-for-user-idx.ts +0 -14
- package/src/data-plane/server/db/migrations/20230808T172902639Z-repo-rev.ts +0 -12
- package/src/data-plane/server/db/migrations/20230810T203349843Z-action-duration.ts +0 -23
- package/src/data-plane/server/db/migrations/20230817T195936007Z-native-notifications.ts +0 -16
- package/src/data-plane/server/db/migrations/20230830T205507322Z-suggested-feeds.ts +0 -13
- package/src/data-plane/server/db/migrations/20230904T211011773Z-block-lists.ts +0 -24
- package/src/data-plane/server/db/migrations/20230906T222220386Z-thread-gating.ts +0 -27
- package/src/data-plane/server/db/migrations/20230920T213858047Z-add-tags-to-post.ts +0 -9
- package/src/data-plane/server/db/migrations/20230929T192920807Z-record-cursor-indexes.ts +0 -40
- package/src/data-plane/server/db/migrations/20231003T202833377Z-create-moderation-subject-status.ts +0 -123
- package/src/data-plane/server/db/migrations/20231220T225126090Z-blob-takedowns.ts +0 -66
- package/src/data-plane/server/db/migrations/20240124T023719200Z-tagged-suggestions.ts +0 -15
- package/src/data-plane/server/db/migrations/20240226T225725627Z-labelers.ts +0 -27
- package/src/data-plane/server/db/migrations/20240530T170337073Z-account-deactivation.ts +0 -12
- package/src/data-plane/server/db/migrations/20240606T171229898Z-thread-mutes.ts +0 -15
- package/src/data-plane/server/db/migrations/20240606T222548219Z-starter-packs.ts +0 -45
- package/src/data-plane/server/db/migrations/20240719T203853939Z-priority-notifs.ts +0 -25
- package/src/data-plane/server/db/migrations/20240723T220700077Z-quotes-post-aggs.ts +0 -12
- package/src/data-plane/server/db/migrations/20240723T220703655Z-quotes.ts +0 -28
- package/src/data-plane/server/db/migrations/20240801T193939827Z-post-gate.ts +0 -17
- package/src/data-plane/server/db/migrations/20240808T224251220Z-post-gate-flags.ts +0 -25
- package/src/data-plane/server/db/migrations/20240829T211238293Z-simplify-actor-sync.ts +0 -23
- package/src/data-plane/server/db/migrations/20240831T134810923Z-pinned-posts.ts +0 -17
- package/src/data-plane/server/db/migrations/20241114T153108102Z-add-starter-packs-name.ts +0 -19
- package/src/data-plane/server/db/migrations/20250116T222618297Z-post-embed-video.ts +0 -17
- package/src/data-plane/server/db/migrations/20250207T174822012Z-add-label-exp.ts +0 -9
- package/src/data-plane/server/db/migrations/20250404T163421487Z-verifications.ts +0 -39
- package/src/data-plane/server/db/migrations/20250526T023712742Z-like-repost-via.ts +0 -17
- package/src/data-plane/server/db/migrations/20250528T221913281Z-add-record-tags.ts +0 -9
- package/src/data-plane/server/db/migrations/20250602T190357447Z-add-private-data.ts +0 -22
- package/src/data-plane/server/db/migrations/20250611T140649895Z-add-activity-subscription.ts +0 -22
- package/src/data-plane/server/db/migrations/20250627T025331240Z-add-actor-age-assurance-columns.ts +0 -22
- package/src/data-plane/server/db/migrations/20250812T183735692Z-add-bookmarks.ts +0 -23
- package/src/data-plane/server/db/migrations/20250813T174955711Z-add-post-agg-bookmarks.ts +0 -12
- package/src/data-plane/server/db/migrations/20251120T004738098Z-update-actor-age-assurance-v2.ts +0 -28
- package/src/data-plane/server/db/migrations/20260112T133951271Z-add-drafts.ts +0 -24
- package/src/data-plane/server/db/migrations/20260604T224952774Z-post-embed-gallery-image.ts +0 -19
- package/src/data-plane/server/db/migrations/index.ts +0 -60
- package/src/data-plane/server/db/migrations/provider.ts +0 -26
- package/src/data-plane/server/db/pagination.ts +0 -341
- package/src/data-plane/server/db/tables/activity-subscription.ts +0 -12
- package/src/data-plane/server/db/tables/actor-block.ts +0 -14
- package/src/data-plane/server/db/tables/actor-state.ts +0 -10
- package/src/data-plane/server/db/tables/actor-sync.ts +0 -9
- package/src/data-plane/server/db/tables/actor.ts +0 -19
- package/src/data-plane/server/db/tables/algo.ts +0 -11
- package/src/data-plane/server/db/tables/blob-takedown.ts +0 -9
- package/src/data-plane/server/db/tables/bookmark.ts +0 -11
- package/src/data-plane/server/db/tables/did-cache.ts +0 -13
- package/src/data-plane/server/db/tables/draft.ts +0 -11
- package/src/data-plane/server/db/tables/duplicate-record.ts +0 -12
- package/src/data-plane/server/db/tables/feed-generator.ts +0 -21
- package/src/data-plane/server/db/tables/feed-item.ts +0 -12
- package/src/data-plane/server/db/tables/follow.ts +0 -15
- package/src/data-plane/server/db/tables/label.ts +0 -13
- package/src/data-plane/server/db/tables/labeler.ts +0 -16
- package/src/data-plane/server/db/tables/like.ts +0 -18
- package/src/data-plane/server/db/tables/list-block.ts +0 -15
- package/src/data-plane/server/db/tables/list-item.ts +0 -16
- package/src/data-plane/server/db/tables/list-mute.ts +0 -9
- package/src/data-plane/server/db/tables/list.ts +0 -19
- package/src/data-plane/server/db/tables/mute.ts +0 -9
- package/src/data-plane/server/db/tables/notification-push-token.ts +0 -10
- package/src/data-plane/server/db/tables/notification.ts +0 -16
- package/src/data-plane/server/db/tables/post-agg.ts +0 -16
- package/src/data-plane/server/db/tables/post-embed.ts +0 -47
- package/src/data-plane/server/db/tables/post-gate.ts +0 -12
- package/src/data-plane/server/db/tables/post.ts +0 -28
- package/src/data-plane/server/db/tables/private-data.ts +0 -13
- package/src/data-plane/server/db/tables/profile-agg.ts +0 -14
- package/src/data-plane/server/db/tables/profile.ts +0 -17
- package/src/data-plane/server/db/tables/quote.ts +0 -15
- package/src/data-plane/server/db/tables/record.ts +0 -15
- package/src/data-plane/server/db/tables/repost.ts +0 -18
- package/src/data-plane/server/db/tables/starter-pack.ts +0 -17
- package/src/data-plane/server/db/tables/subscription.ts +0 -9
- package/src/data-plane/server/db/tables/suggested-feed.ts +0 -10
- package/src/data-plane/server/db/tables/suggested-follow.ts +0 -10
- package/src/data-plane/server/db/tables/tagged-suggestion.ts +0 -11
- package/src/data-plane/server/db/tables/thread-gate.ts +0 -12
- package/src/data-plane/server/db/tables/thread-mute.ts +0 -9
- package/src/data-plane/server/db/tables/verification.ts +0 -20
- package/src/data-plane/server/db/tables/view-param.ts +0 -12
- package/src/data-plane/server/db/types.ts +0 -12
- package/src/data-plane/server/db/util.ts +0 -67
- package/src/data-plane/server/index.ts +0 -44
- package/src/data-plane/server/indexing/index.ts +0 -458
- package/src/data-plane/server/indexing/plugins/block.ts +0 -84
- package/src/data-plane/server/indexing/plugins/chat-declaration.ts +0 -60
- package/src/data-plane/server/indexing/plugins/feed-generator.ts +0 -80
- package/src/data-plane/server/indexing/plugins/follow.ts +0 -132
- package/src/data-plane/server/indexing/plugins/germ-declaration.ts +0 -57
- package/src/data-plane/server/indexing/plugins/labeler.ts +0 -74
- package/src/data-plane/server/indexing/plugins/like.ts +0 -151
- package/src/data-plane/server/indexing/plugins/list-block.ts +0 -84
- package/src/data-plane/server/indexing/plugins/list-item.ts +0 -92
- package/src/data-plane/server/indexing/plugins/list.ts +0 -80
- package/src/data-plane/server/indexing/plugins/notif-declaration.ts +0 -57
- package/src/data-plane/server/indexing/plugins/post-gate.ts +0 -101
- package/src/data-plane/server/indexing/plugins/post.ts +0 -675
- package/src/data-plane/server/indexing/plugins/profile.ts +0 -90
- package/src/data-plane/server/indexing/plugins/repost.ts +0 -176
- package/src/data-plane/server/indexing/plugins/starter-pack.ts +0 -74
- package/src/data-plane/server/indexing/plugins/status.ts +0 -57
- package/src/data-plane/server/indexing/plugins/thread-gate.ts +0 -101
- package/src/data-plane/server/indexing/plugins/verification.ts +0 -113
- package/src/data-plane/server/indexing/processor.ts +0 -292
- package/src/data-plane/server/routes/activity-subscription.ts +0 -84
- package/src/data-plane/server/routes/blocks.ts +0 -127
- package/src/data-plane/server/routes/bookmarks.ts +0 -83
- package/src/data-plane/server/routes/drafts.ts +0 -37
- package/src/data-plane/server/routes/feed-gens.ts +0 -89
- package/src/data-plane/server/routes/feeds.ts +0 -176
- package/src/data-plane/server/routes/follows.ts +0 -141
- package/src/data-plane/server/routes/identity.ts +0 -59
- package/src/data-plane/server/routes/index.ts +0 -67
- package/src/data-plane/server/routes/interactions.ts +0 -120
- package/src/data-plane/server/routes/labels.ts +0 -55
- package/src/data-plane/server/routes/likes.ts +0 -92
- package/src/data-plane/server/routes/lists.ts +0 -88
- package/src/data-plane/server/routes/moderation.ts +0 -102
- package/src/data-plane/server/routes/mutes.ts +0 -195
- package/src/data-plane/server/routes/notifs.ts +0 -239
- package/src/data-plane/server/routes/profile.ts +0 -220
- package/src/data-plane/server/routes/quotes.ts +0 -32
- package/src/data-plane/server/routes/records.ts +0 -119
- package/src/data-plane/server/routes/relationships.ts +0 -174
- package/src/data-plane/server/routes/reposts.ts +0 -76
- package/src/data-plane/server/routes/search.ts +0 -181
- package/src/data-plane/server/routes/site-standard.ts +0 -12
- package/src/data-plane/server/routes/sitemap.ts +0 -43
- package/src/data-plane/server/routes/starter-packs.ts +0 -32
- package/src/data-plane/server/routes/suggestions.ts +0 -175
- package/src/data-plane/server/routes/sync.ts +0 -16
- package/src/data-plane/server/routes/threads.ts +0 -33
- package/src/data-plane/server/subscription.ts +0 -152
- package/src/data-plane/server/util.ts +0 -202
- package/src/error.ts +0 -12
- package/src/etcd.ts +0 -90
- package/src/feature-gates/README.md +0 -83
- package/src/feature-gates/gates.ts +0 -25
- package/src/feature-gates/index.ts +0 -235
- package/src/feature-gates/metrics.test.ts +0 -196
- package/src/feature-gates/metrics.ts +0 -107
- package/src/feature-gates/types.ts +0 -62
- package/src/feature-gates/utils.test.ts +0 -66
- package/src/feature-gates/utils.ts +0 -135
- package/src/hydration/actor.ts +0 -578
- package/src/hydration/external.test.ts +0 -281
- package/src/hydration/external.ts +0 -268
- package/src/hydration/feed.ts +0 -455
- package/src/hydration/graph.ts +0 -354
- package/src/hydration/hydrator.ts +0 -1835
- package/src/hydration/label.ts +0 -207
- package/src/hydration/util.ts +0 -199
- package/src/image/index.ts +0 -2
- package/src/image/invalidator.ts +0 -33
- package/src/image/logger.ts +0 -6
- package/src/image/server.ts +0 -228
- package/src/image/sharp.ts +0 -89
- package/src/image/uri.ts +0 -114
- package/src/image/util.ts +0 -41
- package/src/index.ts +0 -312
- package/src/kws.ts +0 -197
- package/src/logger.ts +0 -40
- package/src/pipeline.ts +0 -60
- package/src/redis.ts +0 -205
- package/src/rolodex.ts +0 -42
- package/src/stash.ts +0 -76
- package/src/util/debug.ts +0 -10
- package/src/util/http.ts +0 -42
- package/src/util/retry.ts +0 -10
- package/src/util/standard-site.test.ts +0 -423
- package/src/util/standard-site.ts +0 -196
- package/src/util/uris.ts +0 -38
- package/src/util.ts +0 -48
- package/src/views/index.ts +0 -2783
- package/src/views/threads-v2.ts +0 -510
- package/src/views/types.ts +0 -193
- package/src/views/util.ts +0 -114
- package/test.env +0 -2
- package/tests/__snapshots__/feed-generation.test.ts.snap +0 -2510
- package/tests/_util.ts +0 -292
- package/tests/admin/admin-auth.test.ts +0 -190
- package/tests/admin/moderation.test.ts +0 -222
- package/tests/auth.test.ts +0 -90
- package/tests/blob-resolver.test.ts +0 -125
- package/tests/data-plane/__snapshots__/indexing.test.ts.snap +0 -887
- package/tests/data-plane/db.test.ts +0 -189
- package/tests/data-plane/duplicate-records.test.ts +0 -156
- package/tests/data-plane/handle-invalidation.test.ts +0 -153
- package/tests/data-plane/indexing.test.ts +0 -827
- package/tests/data-plane/subscription.test.ts +0 -128
- package/tests/data-plane/thread-mutes.test.ts +0 -175
- package/tests/entryway-auth.test.ts +0 -177
- package/tests/etcd.test.ts +0 -302
- package/tests/feed-generation.test.ts +0 -965
- package/tests/hydration/util.test.ts +0 -119
- package/tests/image/server.test.ts +0 -97
- package/tests/image/sharp.test.ts +0 -199
- package/tests/image/uri.test.ts +0 -106
- package/tests/label-hydration.test.ts +0 -245
- package/tests/postgates.test.ts +0 -182
- package/tests/query-labels.test.ts +0 -85
- package/tests/redis-cache.test.ts +0 -230
- package/tests/seed/feed-hidden-replies.ts +0 -63
- package/tests/seed/get-suggested-starter-packs.ts +0 -64
- package/tests/seed/get-trends.ts +0 -71
- package/tests/seed/known-followers.ts +0 -111
- package/tests/seed/postgates.ts +0 -57
- package/tests/server.test.ts +0 -115
- package/tests/sitemap.test.ts +0 -75
- package/tests/stash.test.ts +0 -180
- package/tests/utils.test.ts +0 -36
- package/tests/views/__snapshots__/actor-search.test.ts.snap +0 -155
- package/tests/views/__snapshots__/author-feed.test.ts.snap +0 -6301
- package/tests/views/__snapshots__/block-lists.test.ts.snap +0 -690
- package/tests/views/__snapshots__/blocks.test.ts.snap +0 -462
- package/tests/views/__snapshots__/bookmarks.test.ts.snap +0 -379
- package/tests/views/__snapshots__/follows.test.ts.snap +0 -798
- package/tests/views/__snapshots__/labeler-service.test.ts.snap +0 -233
- package/tests/views/__snapshots__/likes.test.ts.snap +0 -124
- package/tests/views/__snapshots__/list-feed.test.ts.snap +0 -883
- package/tests/views/__snapshots__/lists.test.ts.snap +0 -650
- package/tests/views/__snapshots__/mute-lists.test.ts.snap +0 -705
- package/tests/views/__snapshots__/mutes.test.ts.snap +0 -353
- package/tests/views/__snapshots__/notifications.test.ts.snap +0 -3074
- package/tests/views/__snapshots__/posts.test.ts.snap +0 -1019
- package/tests/views/__snapshots__/profile.test.ts.snap +0 -811
- package/tests/views/__snapshots__/quotes.test.ts.snap +0 -445
- package/tests/views/__snapshots__/reposts.test.ts.snap +0 -112
- package/tests/views/__snapshots__/starter-packs.test.ts.snap +0 -836
- package/tests/views/__snapshots__/thread-v2.test.ts.snap +0 -1298
- package/tests/views/__snapshots__/thread.test.ts.snap +0 -2051
- package/tests/views/__snapshots__/threadgating.test.ts.snap +0 -189
- package/tests/views/__snapshots__/timeline.test.ts.snap +0 -7252
- package/tests/views/account-deactivation.test.ts +0 -81
- package/tests/views/actor-likes.test.ts +0 -138
- package/tests/views/actor-search.test.ts +0 -261
- package/tests/views/age-assurance-v2.test.ts +0 -823
- package/tests/views/age-assurance.test.ts +0 -479
- package/tests/views/author-feed.test.ts +0 -694
- package/tests/views/block-lists.test.ts +0 -661
- package/tests/views/blocks.test.ts +0 -889
- package/tests/views/bookmarks.test.ts +0 -345
- package/tests/views/drafts.test.ts +0 -430
- package/tests/views/feed-hidden-replies.test.ts +0 -243
- package/tests/views/feed-view-post.test.ts +0 -501
- package/tests/views/follows.test.ts +0 -372
- package/tests/views/get-config.test.ts +0 -64
- package/tests/views/get-suggested-onboarding-users.test.ts +0 -193
- package/tests/views/get-suggested-starter-packs.test.ts +0 -137
- package/tests/views/get-trends.test.ts +0 -141
- package/tests/views/internal-actor.test.ts +0 -127
- package/tests/views/known-followers.test.ts +0 -193
- package/tests/views/labeler-service.test.ts +0 -242
- package/tests/views/labels-needs-review.test.ts +0 -316
- package/tests/views/labels-takedown.test.ts +0 -247
- package/tests/views/likes.test.ts +0 -192
- package/tests/views/list-feed.test.ts +0 -195
- package/tests/views/lists.test.ts +0 -412
- package/tests/views/mute-lists.test.ts +0 -509
- package/tests/views/mutes.test.ts +0 -308
- package/tests/views/notifications.test.ts +0 -1581
- package/tests/views/post-search.test.ts +0 -281
- package/tests/views/posts-debug.test.ts +0 -79
- package/tests/views/posts.test.ts +0 -427
- package/tests/views/profile-debug.test.ts +0 -75
- package/tests/views/profile.test.ts +0 -795
- package/tests/views/quotes.test.ts +0 -133
- package/tests/views/reposts.test.ts +0 -112
- package/tests/views/starter-packs.test.ts +0 -395
- package/tests/views/suggestions.test.ts +0 -145
- package/tests/views/thread-v2.test.ts +0 -2005
- package/tests/views/thread.test.ts +0 -637
- package/tests/views/threadgating.test.ts +0 -843
- package/tests/views/timeline.test.ts +0 -328
- package/tests/views/verification.test.ts +0 -296
- package/tsconfig.build.json +0 -10
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -7
- package/tsconfig.tests.json +0 -8
- package/vitest.config.ts +0 -10
|
@@ -1,1581 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
afterAll,
|
|
3
|
-
beforeAll,
|
|
4
|
-
beforeEach,
|
|
5
|
-
describe,
|
|
6
|
-
expect,
|
|
7
|
-
it,
|
|
8
|
-
vi,
|
|
9
|
-
} from 'vitest'
|
|
10
|
-
import {
|
|
11
|
-
AppBskyActorDefs,
|
|
12
|
-
AppBskyNotificationDeclaration,
|
|
13
|
-
AppBskyNotificationDefs,
|
|
14
|
-
AppBskyNotificationListActivitySubscriptions,
|
|
15
|
-
AppBskyNotificationListNotifications,
|
|
16
|
-
AppBskyNotificationPutPreferencesV2,
|
|
17
|
-
AtpAgent,
|
|
18
|
-
ids,
|
|
19
|
-
} from '@atproto/api'
|
|
20
|
-
import {
|
|
21
|
-
SeedClient,
|
|
22
|
-
TestNetwork,
|
|
23
|
-
basicSeed,
|
|
24
|
-
seedThreadV2,
|
|
25
|
-
} from '@atproto/dev-env'
|
|
26
|
-
import type { DidString } from '@atproto/syntax'
|
|
27
|
-
import { delayCursor } from '../../src/api/app/bsky/notification/listNotifications.js'
|
|
28
|
-
import { Namespaces } from '../../src/stash.js'
|
|
29
|
-
import { forSnapshot, paginateAll } from '../_util.js'
|
|
30
|
-
|
|
31
|
-
type Database = TestNetwork['bsky']['db']
|
|
32
|
-
|
|
33
|
-
describe('notification views', () => {
|
|
34
|
-
let network: TestNetwork
|
|
35
|
-
let db: Database
|
|
36
|
-
|
|
37
|
-
let agent: AtpAgent
|
|
38
|
-
let pdsAgent: AtpAgent
|
|
39
|
-
let sc: SeedClient
|
|
40
|
-
|
|
41
|
-
// account dids, for convenience
|
|
42
|
-
let alice: DidString
|
|
43
|
-
let bob: DidString
|
|
44
|
-
let carol: DidString
|
|
45
|
-
let dan: DidString
|
|
46
|
-
let eve: DidString
|
|
47
|
-
let fred: DidString
|
|
48
|
-
let greg: DidString
|
|
49
|
-
let han: DidString
|
|
50
|
-
let blocked: DidString
|
|
51
|
-
|
|
52
|
-
beforeAll(async () => {
|
|
53
|
-
network = await TestNetwork.create({
|
|
54
|
-
dbPostgresSchema: 'bsky_views_notifications',
|
|
55
|
-
bsky: {
|
|
56
|
-
threadTagsHide: new Set([seedThreadV2.TAG_HIDE]),
|
|
57
|
-
},
|
|
58
|
-
})
|
|
59
|
-
db = network.bsky.db
|
|
60
|
-
agent = network.bsky.getAgent()
|
|
61
|
-
pdsAgent = network.pds.getAgent()
|
|
62
|
-
sc = network.getSeedClient()
|
|
63
|
-
await basicSeed(sc)
|
|
64
|
-
await network.bsky.db.db
|
|
65
|
-
.updateTable('actor')
|
|
66
|
-
.set({ trustedVerifier: true })
|
|
67
|
-
.where('did', '=', alice)
|
|
68
|
-
.execute()
|
|
69
|
-
await sc.createAccount('eve', {
|
|
70
|
-
email: 'eve@test.com',
|
|
71
|
-
handle: 'eve.test',
|
|
72
|
-
password: 'eve-pass',
|
|
73
|
-
})
|
|
74
|
-
await sc.createAccount('fred', {
|
|
75
|
-
email: 'fred@test.com',
|
|
76
|
-
handle: 'fred.test',
|
|
77
|
-
password: 'fred-pass',
|
|
78
|
-
})
|
|
79
|
-
await sc.createAccount('greg', {
|
|
80
|
-
email: 'greg@test.com',
|
|
81
|
-
handle: 'greg.test',
|
|
82
|
-
password: 'greg-pass',
|
|
83
|
-
})
|
|
84
|
-
await sc.createAccount('han', {
|
|
85
|
-
email: 'han@test.com',
|
|
86
|
-
handle: 'han.test',
|
|
87
|
-
password: 'han-pass',
|
|
88
|
-
})
|
|
89
|
-
await sc.createAccount('blocked', {
|
|
90
|
-
email: 'blocked@test.com',
|
|
91
|
-
handle: 'blocked.test',
|
|
92
|
-
password: 'blocked-pass',
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
alice = sc.dids.alice
|
|
96
|
-
bob = sc.dids.bob
|
|
97
|
-
carol = sc.dids.carol
|
|
98
|
-
dan = sc.dids.dan
|
|
99
|
-
eve = sc.dids.eve
|
|
100
|
-
fred = sc.dids.fred
|
|
101
|
-
greg = sc.dids.greg
|
|
102
|
-
han = sc.dids.han
|
|
103
|
-
blocked = sc.dids.blocked
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
beforeEach(async () => network.processAll())
|
|
107
|
-
afterAll(async () => network?.close())
|
|
108
|
-
|
|
109
|
-
const sortNotifs = (
|
|
110
|
-
notifs: AppBskyNotificationListNotifications.Notification[],
|
|
111
|
-
) => {
|
|
112
|
-
// Need to sort because notification ordering is not well-defined
|
|
113
|
-
return notifs.sort((a, b) => {
|
|
114
|
-
const stableUriA = a.uri.replace(
|
|
115
|
-
/\/did:plc:.+?\//,
|
|
116
|
-
`/${a.author.handle}/`,
|
|
117
|
-
)
|
|
118
|
-
const stableUriB = b.uri.replace(
|
|
119
|
-
/\/did:plc:.+?\//,
|
|
120
|
-
`/${b.author.handle}/`,
|
|
121
|
-
)
|
|
122
|
-
if (stableUriA === stableUriB) {
|
|
123
|
-
return a.indexedAt > b.indexedAt ? -1 : 1
|
|
124
|
-
}
|
|
125
|
-
return stableUriA > stableUriB ? -1 : 1
|
|
126
|
-
})
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
it('fetches notification count without a last-seen', async () => {
|
|
130
|
-
const notifCountAlice =
|
|
131
|
-
await agent.api.app.bsky.notification.getUnreadCount(
|
|
132
|
-
{},
|
|
133
|
-
{
|
|
134
|
-
headers: await network.serviceHeaders(
|
|
135
|
-
alice,
|
|
136
|
-
ids.AppBskyNotificationGetUnreadCount,
|
|
137
|
-
),
|
|
138
|
-
},
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
expect(notifCountAlice.data.count).toBe(12)
|
|
142
|
-
|
|
143
|
-
const notifCountBob = await agent.api.app.bsky.notification.getUnreadCount(
|
|
144
|
-
{},
|
|
145
|
-
{
|
|
146
|
-
headers: await network.serviceHeaders(
|
|
147
|
-
sc.dids.bob,
|
|
148
|
-
ids.AppBskyNotificationGetUnreadCount,
|
|
149
|
-
),
|
|
150
|
-
},
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
expect(notifCountBob.data.count).toBeGreaterThanOrEqual(3)
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
it('generates notifications for all reply ancestors', async () => {
|
|
157
|
-
// Add to reply chain, post ancestors: alice -> bob -> alice -> carol.
|
|
158
|
-
// Should have added one notification for each of alice and bob.
|
|
159
|
-
await sc.reply(
|
|
160
|
-
sc.dids.carol,
|
|
161
|
-
sc.posts[alice][1].ref,
|
|
162
|
-
sc.replies[alice][0].ref,
|
|
163
|
-
'indeed',
|
|
164
|
-
)
|
|
165
|
-
await network.processAll()
|
|
166
|
-
|
|
167
|
-
const notifCountAlice =
|
|
168
|
-
await agent.api.app.bsky.notification.getUnreadCount(
|
|
169
|
-
{},
|
|
170
|
-
{
|
|
171
|
-
headers: await network.serviceHeaders(
|
|
172
|
-
alice,
|
|
173
|
-
ids.AppBskyNotificationGetUnreadCount,
|
|
174
|
-
),
|
|
175
|
-
},
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
expect(notifCountAlice.data.count).toBe(13)
|
|
179
|
-
|
|
180
|
-
const notifCountBob = await agent.api.app.bsky.notification.getUnreadCount(
|
|
181
|
-
{},
|
|
182
|
-
{
|
|
183
|
-
headers: await network.serviceHeaders(
|
|
184
|
-
sc.dids.bob,
|
|
185
|
-
ids.AppBskyNotificationGetUnreadCount,
|
|
186
|
-
),
|
|
187
|
-
},
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
expect(notifCountBob.data.count).toBeGreaterThanOrEqual(4)
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
it('does not give notifs for a deleted subject', async () => {
|
|
194
|
-
const root = await sc.post(sc.dids.alice, 'root')
|
|
195
|
-
const first = await sc.reply(sc.dids.bob, root.ref, root.ref, 'first')
|
|
196
|
-
await sc.deletePost(sc.dids.alice, root.ref.uri)
|
|
197
|
-
const second = await sc.reply(sc.dids.carol, root.ref, first.ref, 'second')
|
|
198
|
-
await network.processAll()
|
|
199
|
-
|
|
200
|
-
const notifsAlice = await agent.api.app.bsky.notification.listNotifications(
|
|
201
|
-
{},
|
|
202
|
-
{
|
|
203
|
-
headers: await network.serviceHeaders(
|
|
204
|
-
sc.dids.alice,
|
|
205
|
-
ids.AppBskyNotificationListNotifications,
|
|
206
|
-
),
|
|
207
|
-
},
|
|
208
|
-
)
|
|
209
|
-
const hasNotif = notifsAlice.data.notifications.some(
|
|
210
|
-
(notif) => notif.uri === second.ref.uriStr,
|
|
211
|
-
)
|
|
212
|
-
expect(hasNotif).toBe(false)
|
|
213
|
-
|
|
214
|
-
// cleanup
|
|
215
|
-
await sc.deletePost(sc.dids.bob, first.ref.uri)
|
|
216
|
-
await sc.deletePost(sc.dids.carol, second.ref.uri)
|
|
217
|
-
await network.processAll()
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
it('generates notifications for quotes', async () => {
|
|
221
|
-
// Dan was quoted by alice
|
|
222
|
-
const notifsDan = await agent.api.app.bsky.notification.listNotifications(
|
|
223
|
-
{},
|
|
224
|
-
{
|
|
225
|
-
headers: await network.serviceHeaders(
|
|
226
|
-
sc.dids.dan,
|
|
227
|
-
ids.AppBskyNotificationListNotifications,
|
|
228
|
-
),
|
|
229
|
-
},
|
|
230
|
-
)
|
|
231
|
-
expect(
|
|
232
|
-
forSnapshot(sortNotifs(notifsDan.data.notifications)),
|
|
233
|
-
).toMatchSnapshot()
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
it('generates notifications for likes', async () => {
|
|
237
|
-
const notifsAlice = await agent.app.bsky.notification.listNotifications(
|
|
238
|
-
{},
|
|
239
|
-
{
|
|
240
|
-
headers: await network.serviceHeaders(
|
|
241
|
-
alice,
|
|
242
|
-
ids.AppBskyNotificationListNotifications,
|
|
243
|
-
),
|
|
244
|
-
},
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
const na = sortNotifs(
|
|
248
|
-
notifsAlice.data.notifications.filter((n) => n.reason === 'like'),
|
|
249
|
-
)
|
|
250
|
-
expect(na).toHaveLength(5)
|
|
251
|
-
expect(forSnapshot(na)).toMatchSnapshot()
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
it('generates notifications for reposts', async () => {
|
|
255
|
-
const notifsAlice = await agent.app.bsky.notification.listNotifications(
|
|
256
|
-
{},
|
|
257
|
-
{
|
|
258
|
-
headers: await network.serviceHeaders(
|
|
259
|
-
alice,
|
|
260
|
-
ids.AppBskyNotificationListNotifications,
|
|
261
|
-
),
|
|
262
|
-
},
|
|
263
|
-
)
|
|
264
|
-
|
|
265
|
-
const na = sortNotifs(
|
|
266
|
-
notifsAlice.data.notifications.filter((n) => n.reason === 'repost'),
|
|
267
|
-
)
|
|
268
|
-
expect(na).toHaveLength(2)
|
|
269
|
-
expect(forSnapshot(na)).toMatchSnapshot()
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
it('generates notifications for likes via repost', async () => {
|
|
273
|
-
const op = dan
|
|
274
|
-
const reposter = carol
|
|
275
|
-
const liker = alice
|
|
276
|
-
await sc.like(liker, sc.posts[op][1].ref, {
|
|
277
|
-
via: sc.reposts[reposter][0].raw,
|
|
278
|
-
})
|
|
279
|
-
await network.processAll()
|
|
280
|
-
|
|
281
|
-
const notifsOp = await agent.app.bsky.notification.listNotifications(
|
|
282
|
-
{},
|
|
283
|
-
{
|
|
284
|
-
headers: await network.serviceHeaders(
|
|
285
|
-
op,
|
|
286
|
-
ids.AppBskyNotificationListNotifications,
|
|
287
|
-
),
|
|
288
|
-
},
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
const no = sortNotifs(
|
|
292
|
-
notifsOp.data.notifications.filter((n) => n.reason === 'like'),
|
|
293
|
-
)
|
|
294
|
-
// Like from `alice` in this test.
|
|
295
|
-
expect(no).toHaveLength(1)
|
|
296
|
-
expect(forSnapshot(no)).toMatchSnapshot()
|
|
297
|
-
|
|
298
|
-
const notifsReposter = await agent.app.bsky.notification.listNotifications(
|
|
299
|
-
{},
|
|
300
|
-
{
|
|
301
|
-
headers: await network.serviceHeaders(
|
|
302
|
-
reposter,
|
|
303
|
-
ids.AppBskyNotificationListNotifications,
|
|
304
|
-
),
|
|
305
|
-
},
|
|
306
|
-
)
|
|
307
|
-
|
|
308
|
-
const nr = sortNotifs(
|
|
309
|
-
notifsReposter.data.notifications.filter(
|
|
310
|
-
(n) => n.reason === 'like-via-repost',
|
|
311
|
-
),
|
|
312
|
-
)
|
|
313
|
-
// Like from `alice` in this test.
|
|
314
|
-
expect(nr).toHaveLength(1)
|
|
315
|
-
expect(forSnapshot(nr)).toMatchSnapshot()
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
it('does not generate self notifications for likes via own repost', async () => {
|
|
319
|
-
const op = dan
|
|
320
|
-
const reposter = carol
|
|
321
|
-
await sc.like(reposter, sc.posts[op][1].ref, {
|
|
322
|
-
via: sc.reposts[reposter][0].raw,
|
|
323
|
-
})
|
|
324
|
-
await network.processAll()
|
|
325
|
-
|
|
326
|
-
const notifsOp = await agent.app.bsky.notification.listNotifications(
|
|
327
|
-
{},
|
|
328
|
-
{
|
|
329
|
-
headers: await network.serviceHeaders(
|
|
330
|
-
op,
|
|
331
|
-
ids.AppBskyNotificationListNotifications,
|
|
332
|
-
),
|
|
333
|
-
},
|
|
334
|
-
)
|
|
335
|
-
|
|
336
|
-
const no = sortNotifs(
|
|
337
|
-
notifsOp.data.notifications.filter((n) => n.reason === 'like'),
|
|
338
|
-
)
|
|
339
|
-
// Like from `alice` in previous test + `carol` on this test.
|
|
340
|
-
expect(no).toHaveLength(2)
|
|
341
|
-
expect(forSnapshot(no)).toMatchSnapshot()
|
|
342
|
-
|
|
343
|
-
const notifsReposter = await agent.app.bsky.notification.listNotifications(
|
|
344
|
-
{},
|
|
345
|
-
{
|
|
346
|
-
headers: await network.serviceHeaders(
|
|
347
|
-
reposter,
|
|
348
|
-
ids.AppBskyNotificationListNotifications,
|
|
349
|
-
),
|
|
350
|
-
},
|
|
351
|
-
)
|
|
352
|
-
|
|
353
|
-
const nr = sortNotifs(
|
|
354
|
-
notifsReposter.data.notifications.filter(
|
|
355
|
-
(n) => n.reason === 'like-via-repost',
|
|
356
|
-
),
|
|
357
|
-
)
|
|
358
|
-
// Like from `alice` in previous test.
|
|
359
|
-
expect(nr).toHaveLength(1)
|
|
360
|
-
expect(forSnapshot(nr)).toMatchSnapshot()
|
|
361
|
-
})
|
|
362
|
-
|
|
363
|
-
it('generates notifications for reposts via repost', async () => {
|
|
364
|
-
const op = dan
|
|
365
|
-
const reposter = carol
|
|
366
|
-
const reReposter = alice
|
|
367
|
-
await sc.repost(reReposter, sc.posts[op][1].ref, {
|
|
368
|
-
via: sc.reposts[reposter][0].raw,
|
|
369
|
-
})
|
|
370
|
-
await network.processAll()
|
|
371
|
-
|
|
372
|
-
const notifsOp = await agent.app.bsky.notification.listNotifications(
|
|
373
|
-
{},
|
|
374
|
-
{
|
|
375
|
-
headers: await network.serviceHeaders(
|
|
376
|
-
op,
|
|
377
|
-
ids.AppBskyNotificationListNotifications,
|
|
378
|
-
),
|
|
379
|
-
},
|
|
380
|
-
)
|
|
381
|
-
|
|
382
|
-
const no = sortNotifs(
|
|
383
|
-
notifsOp.data.notifications.filter((n) => n.reason === 'repost'),
|
|
384
|
-
)
|
|
385
|
-
// Repost from `carol` in seeds + `alice` on this test.
|
|
386
|
-
expect(no).toHaveLength(2)
|
|
387
|
-
expect(forSnapshot(no)).toMatchSnapshot()
|
|
388
|
-
|
|
389
|
-
const notifsReposter = await agent.app.bsky.notification.listNotifications(
|
|
390
|
-
{},
|
|
391
|
-
{
|
|
392
|
-
headers: await network.serviceHeaders(
|
|
393
|
-
reposter,
|
|
394
|
-
ids.AppBskyNotificationListNotifications,
|
|
395
|
-
),
|
|
396
|
-
},
|
|
397
|
-
)
|
|
398
|
-
|
|
399
|
-
const nr = sortNotifs(
|
|
400
|
-
notifsReposter.data.notifications.filter(
|
|
401
|
-
(n) => n.reason === 'repost-via-repost',
|
|
402
|
-
),
|
|
403
|
-
)
|
|
404
|
-
// Repost from `alice` in this test.
|
|
405
|
-
expect(nr).toHaveLength(1)
|
|
406
|
-
expect(forSnapshot(nr)).toMatchSnapshot()
|
|
407
|
-
})
|
|
408
|
-
|
|
409
|
-
it('generates notifications for verification created and removed', async () => {
|
|
410
|
-
await sc.verify(
|
|
411
|
-
sc.dids.alice,
|
|
412
|
-
sc.dids.bob,
|
|
413
|
-
sc.accounts[sc.dids.bob].handle,
|
|
414
|
-
sc.profiles[sc.dids.bob].displayName,
|
|
415
|
-
)
|
|
416
|
-
await network.processAll()
|
|
417
|
-
const notifsBob1 = await agent.app.bsky.notification.listNotifications(
|
|
418
|
-
{ reasons: ['verified', 'unverified'] },
|
|
419
|
-
{
|
|
420
|
-
headers: await network.serviceHeaders(
|
|
421
|
-
sc.dids.bob,
|
|
422
|
-
ids.AppBskyNotificationListNotifications,
|
|
423
|
-
),
|
|
424
|
-
},
|
|
425
|
-
)
|
|
426
|
-
expect(
|
|
427
|
-
forSnapshot(sortNotifs(notifsBob1.data.notifications)),
|
|
428
|
-
).toMatchSnapshot()
|
|
429
|
-
|
|
430
|
-
await sc.unverify(sc.dids.alice, sc.dids.bob)
|
|
431
|
-
await network.processAll()
|
|
432
|
-
const notifsBob2 = await agent.app.bsky.notification.listNotifications(
|
|
433
|
-
{ reasons: ['verified', 'unverified'] },
|
|
434
|
-
{
|
|
435
|
-
headers: await network.serviceHeaders(
|
|
436
|
-
sc.dids.bob,
|
|
437
|
-
ids.AppBskyNotificationListNotifications,
|
|
438
|
-
),
|
|
439
|
-
},
|
|
440
|
-
)
|
|
441
|
-
expect(
|
|
442
|
-
forSnapshot(sortNotifs(notifsBob2.data.notifications)),
|
|
443
|
-
).toMatchSnapshot()
|
|
444
|
-
})
|
|
445
|
-
|
|
446
|
-
it('fetches notifications without a last-seen', async () => {
|
|
447
|
-
const notifRes = await agent.api.app.bsky.notification.listNotifications(
|
|
448
|
-
{},
|
|
449
|
-
{
|
|
450
|
-
headers: await network.serviceHeaders(
|
|
451
|
-
alice,
|
|
452
|
-
ids.AppBskyNotificationListNotifications,
|
|
453
|
-
),
|
|
454
|
-
},
|
|
455
|
-
)
|
|
456
|
-
|
|
457
|
-
const notifs = notifRes.data.notifications
|
|
458
|
-
expect(notifs.length).toBe(13)
|
|
459
|
-
|
|
460
|
-
const readStates = notifs.map((notif) => notif.isRead)
|
|
461
|
-
expect(readStates).toEqual(notifs.map((_, i) => i !== 0)) // only first appears unread
|
|
462
|
-
|
|
463
|
-
expect(forSnapshot(sortNotifs(notifs))).toMatchSnapshot()
|
|
464
|
-
})
|
|
465
|
-
|
|
466
|
-
it('paginates', async () => {
|
|
467
|
-
const results = (
|
|
468
|
-
results: AppBskyNotificationListNotifications.OutputSchema[],
|
|
469
|
-
) => sortNotifs(results.flatMap((res) => res.notifications))
|
|
470
|
-
const paginator = async (cursor?: string) => {
|
|
471
|
-
const res = await agent.api.app.bsky.notification.listNotifications(
|
|
472
|
-
{ cursor, limit: 6 },
|
|
473
|
-
{
|
|
474
|
-
headers: await network.serviceHeaders(
|
|
475
|
-
alice,
|
|
476
|
-
ids.AppBskyNotificationListNotifications,
|
|
477
|
-
),
|
|
478
|
-
},
|
|
479
|
-
)
|
|
480
|
-
return res.data
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
const paginatedAll = await paginateAll(paginator)
|
|
484
|
-
paginatedAll.forEach((res) =>
|
|
485
|
-
expect(res.notifications.length).toBeLessThanOrEqual(6),
|
|
486
|
-
)
|
|
487
|
-
|
|
488
|
-
const full = await agent.api.app.bsky.notification.listNotifications(
|
|
489
|
-
{},
|
|
490
|
-
{
|
|
491
|
-
headers: await network.serviceHeaders(
|
|
492
|
-
alice,
|
|
493
|
-
ids.AppBskyNotificationListNotifications,
|
|
494
|
-
),
|
|
495
|
-
},
|
|
496
|
-
)
|
|
497
|
-
|
|
498
|
-
expect(full.data.notifications.length).toEqual(13)
|
|
499
|
-
expect(results(paginatedAll)).toEqual(results([full.data]))
|
|
500
|
-
})
|
|
501
|
-
|
|
502
|
-
it('fetches notification count with a last-seen', async () => {
|
|
503
|
-
const full = await agent.api.app.bsky.notification.listNotifications(
|
|
504
|
-
{},
|
|
505
|
-
{
|
|
506
|
-
headers: await network.serviceHeaders(
|
|
507
|
-
alice,
|
|
508
|
-
ids.AppBskyNotificationListNotifications,
|
|
509
|
-
),
|
|
510
|
-
},
|
|
511
|
-
)
|
|
512
|
-
const seenAt = full.data.notifications[3].indexedAt
|
|
513
|
-
await agent.api.app.bsky.notification.updateSeen(
|
|
514
|
-
{ seenAt },
|
|
515
|
-
{
|
|
516
|
-
headers: await network.serviceHeaders(
|
|
517
|
-
alice,
|
|
518
|
-
ids.AppBskyNotificationUpdateSeen,
|
|
519
|
-
),
|
|
520
|
-
encoding: 'application/json',
|
|
521
|
-
},
|
|
522
|
-
)
|
|
523
|
-
const full2 = await agent.api.app.bsky.notification.listNotifications(
|
|
524
|
-
{},
|
|
525
|
-
{
|
|
526
|
-
headers: await network.serviceHeaders(
|
|
527
|
-
alice,
|
|
528
|
-
ids.AppBskyNotificationListNotifications,
|
|
529
|
-
),
|
|
530
|
-
},
|
|
531
|
-
)
|
|
532
|
-
expect(full2.data.notifications.length).toBe(full.data.notifications.length)
|
|
533
|
-
expect(full2.data.seenAt).toEqual(seenAt)
|
|
534
|
-
|
|
535
|
-
const notifCount = await agent.api.app.bsky.notification.getUnreadCount(
|
|
536
|
-
{},
|
|
537
|
-
{
|
|
538
|
-
headers: await network.serviceHeaders(
|
|
539
|
-
alice,
|
|
540
|
-
ids.AppBskyNotificationGetUnreadCount,
|
|
541
|
-
),
|
|
542
|
-
},
|
|
543
|
-
)
|
|
544
|
-
|
|
545
|
-
expect(notifCount.data.count).toBe(
|
|
546
|
-
full.data.notifications.filter((n) => n.indexedAt > seenAt).length,
|
|
547
|
-
)
|
|
548
|
-
expect(notifCount.data.count).toBeGreaterThan(0)
|
|
549
|
-
|
|
550
|
-
// reset last-seen
|
|
551
|
-
await agent.api.app.bsky.notification.updateSeen(
|
|
552
|
-
{ seenAt: new Date(0).toISOString() },
|
|
553
|
-
{
|
|
554
|
-
headers: await network.serviceHeaders(
|
|
555
|
-
alice,
|
|
556
|
-
ids.AppBskyNotificationUpdateSeen,
|
|
557
|
-
),
|
|
558
|
-
encoding: 'application/json',
|
|
559
|
-
},
|
|
560
|
-
)
|
|
561
|
-
})
|
|
562
|
-
|
|
563
|
-
it('fetches notifications with a last-seen', async () => {
|
|
564
|
-
const full = await agent.api.app.bsky.notification.listNotifications(
|
|
565
|
-
{},
|
|
566
|
-
{
|
|
567
|
-
headers: await network.serviceHeaders(
|
|
568
|
-
alice,
|
|
569
|
-
ids.AppBskyNotificationListNotifications,
|
|
570
|
-
),
|
|
571
|
-
},
|
|
572
|
-
)
|
|
573
|
-
const seenAt = full.data.notifications[3].indexedAt
|
|
574
|
-
await agent.api.app.bsky.notification.updateSeen(
|
|
575
|
-
{ seenAt },
|
|
576
|
-
{
|
|
577
|
-
headers: await network.serviceHeaders(
|
|
578
|
-
alice,
|
|
579
|
-
ids.AppBskyNotificationUpdateSeen,
|
|
580
|
-
),
|
|
581
|
-
encoding: 'application/json',
|
|
582
|
-
},
|
|
583
|
-
)
|
|
584
|
-
const notifRes = await agent.api.app.bsky.notification.listNotifications(
|
|
585
|
-
{},
|
|
586
|
-
{
|
|
587
|
-
headers: await network.serviceHeaders(
|
|
588
|
-
alice,
|
|
589
|
-
ids.AppBskyNotificationListNotifications,
|
|
590
|
-
),
|
|
591
|
-
},
|
|
592
|
-
)
|
|
593
|
-
|
|
594
|
-
const notifs = notifRes.data.notifications
|
|
595
|
-
expect(notifs.length).toBe(13)
|
|
596
|
-
|
|
597
|
-
const readStates = notifs.map((notif) => notif.isRead)
|
|
598
|
-
expect(readStates).toEqual(notifs.map((n) => n.indexedAt < seenAt))
|
|
599
|
-
// reset last-seen
|
|
600
|
-
await agent.api.app.bsky.notification.updateSeen(
|
|
601
|
-
{ seenAt: new Date(0).toISOString() },
|
|
602
|
-
{
|
|
603
|
-
headers: await network.serviceHeaders(
|
|
604
|
-
alice,
|
|
605
|
-
ids.AppBskyNotificationUpdateSeen,
|
|
606
|
-
),
|
|
607
|
-
encoding: 'application/json',
|
|
608
|
-
},
|
|
609
|
-
)
|
|
610
|
-
})
|
|
611
|
-
|
|
612
|
-
it('fetches notifications omitting mentions and replies for taken-down posts', async () => {
|
|
613
|
-
const postRef1 = sc.replies[sc.dids.carol][0].ref // Reply
|
|
614
|
-
const postRef2 = sc.posts[sc.dids.dan][1].ref // Mention
|
|
615
|
-
await Promise.all(
|
|
616
|
-
[postRef1, postRef2].map((postRef) =>
|
|
617
|
-
network.bsky.ctx.dataplane.takedownRecord({
|
|
618
|
-
recordUri: postRef.uriStr,
|
|
619
|
-
}),
|
|
620
|
-
),
|
|
621
|
-
)
|
|
622
|
-
|
|
623
|
-
const notifRes = await agent.api.app.bsky.notification.listNotifications(
|
|
624
|
-
{},
|
|
625
|
-
{
|
|
626
|
-
headers: await network.serviceHeaders(
|
|
627
|
-
alice,
|
|
628
|
-
ids.AppBskyNotificationListNotifications,
|
|
629
|
-
),
|
|
630
|
-
},
|
|
631
|
-
)
|
|
632
|
-
const notifCount = await agent.api.app.bsky.notification.getUnreadCount(
|
|
633
|
-
{},
|
|
634
|
-
{
|
|
635
|
-
headers: await network.serviceHeaders(
|
|
636
|
-
alice,
|
|
637
|
-
ids.AppBskyNotificationGetUnreadCount,
|
|
638
|
-
),
|
|
639
|
-
},
|
|
640
|
-
)
|
|
641
|
-
|
|
642
|
-
const notifs = sortNotifs(notifRes.data.notifications)
|
|
643
|
-
expect(notifs.length).toBe(11)
|
|
644
|
-
expect(forSnapshot(notifs)).toMatchSnapshot()
|
|
645
|
-
expect(notifCount.data.count).toBe(11)
|
|
646
|
-
|
|
647
|
-
// Cleanup
|
|
648
|
-
await Promise.all(
|
|
649
|
-
[postRef1, postRef2].map((postRef) =>
|
|
650
|
-
network.bsky.ctx.dataplane.untakedownRecord({
|
|
651
|
-
recordUri: postRef.uriStr,
|
|
652
|
-
}),
|
|
653
|
-
),
|
|
654
|
-
)
|
|
655
|
-
})
|
|
656
|
-
|
|
657
|
-
it('fetches notifications with explicit priority', async () => {
|
|
658
|
-
const priority = await agent.api.app.bsky.notification.listNotifications(
|
|
659
|
-
{ priority: true },
|
|
660
|
-
{
|
|
661
|
-
headers: await network.serviceHeaders(
|
|
662
|
-
sc.dids.carol,
|
|
663
|
-
ids.AppBskyNotificationListNotifications,
|
|
664
|
-
),
|
|
665
|
-
},
|
|
666
|
-
)
|
|
667
|
-
// only notifs from follow (alice)
|
|
668
|
-
expect(
|
|
669
|
-
priority.data.notifications.every(
|
|
670
|
-
(notif) =>
|
|
671
|
-
!([sc.dids.bob, sc.dids.dan] as string[]).includes(notif.author.did),
|
|
672
|
-
),
|
|
673
|
-
).toBe(true)
|
|
674
|
-
expect(forSnapshot(priority.data)).toMatchSnapshot()
|
|
675
|
-
const noPriority = await agent.api.app.bsky.notification.listNotifications(
|
|
676
|
-
{ priority: false },
|
|
677
|
-
{
|
|
678
|
-
headers: await network.serviceHeaders(
|
|
679
|
-
sc.dids.carol,
|
|
680
|
-
ids.AppBskyNotificationListNotifications,
|
|
681
|
-
),
|
|
682
|
-
},
|
|
683
|
-
)
|
|
684
|
-
expect(forSnapshot(noPriority.data)).toMatchSnapshot()
|
|
685
|
-
})
|
|
686
|
-
|
|
687
|
-
it('fetches notifications with default priority', async () => {
|
|
688
|
-
await agent.api.app.bsky.notification.putPreferences(
|
|
689
|
-
{ priority: true },
|
|
690
|
-
{
|
|
691
|
-
encoding: 'application/json',
|
|
692
|
-
headers: await network.serviceHeaders(
|
|
693
|
-
sc.dids.carol,
|
|
694
|
-
ids.AppBskyNotificationPutPreferences,
|
|
695
|
-
),
|
|
696
|
-
},
|
|
697
|
-
)
|
|
698
|
-
await network.processAll()
|
|
699
|
-
const notifs = await agent.api.app.bsky.notification.listNotifications(
|
|
700
|
-
{},
|
|
701
|
-
{
|
|
702
|
-
headers: await network.serviceHeaders(
|
|
703
|
-
sc.dids.carol,
|
|
704
|
-
ids.AppBskyNotificationListNotifications,
|
|
705
|
-
),
|
|
706
|
-
},
|
|
707
|
-
)
|
|
708
|
-
// only notifs from follow (alice)
|
|
709
|
-
expect(
|
|
710
|
-
notifs.data.notifications.every(
|
|
711
|
-
(notif) =>
|
|
712
|
-
!([sc.dids.bob, sc.dids.dan] as string[]).includes(notif.author.did),
|
|
713
|
-
),
|
|
714
|
-
).toBe(true)
|
|
715
|
-
expect(forSnapshot(notifs.data)).toMatchSnapshot()
|
|
716
|
-
await agent.api.app.bsky.notification.putPreferences(
|
|
717
|
-
{ priority: false },
|
|
718
|
-
{
|
|
719
|
-
encoding: 'application/json',
|
|
720
|
-
headers: await network.serviceHeaders(
|
|
721
|
-
sc.dids.carol,
|
|
722
|
-
ids.AppBskyNotificationPutPreferences,
|
|
723
|
-
),
|
|
724
|
-
},
|
|
725
|
-
)
|
|
726
|
-
await network.processAll()
|
|
727
|
-
})
|
|
728
|
-
|
|
729
|
-
it('filters notifications by reason', async () => {
|
|
730
|
-
const res = await agent.app.bsky.notification.listNotifications(
|
|
731
|
-
{
|
|
732
|
-
// Pin priority so the snapshot doesn't race with the viewer's stored
|
|
733
|
-
// priority preference, which neighbouring tests mutate.
|
|
734
|
-
priority: false,
|
|
735
|
-
reasons: ['mention'],
|
|
736
|
-
},
|
|
737
|
-
{
|
|
738
|
-
headers: await network.serviceHeaders(
|
|
739
|
-
sc.dids.alice,
|
|
740
|
-
ids.AppBskyNotificationListNotifications,
|
|
741
|
-
),
|
|
742
|
-
},
|
|
743
|
-
)
|
|
744
|
-
expect(res.data.notifications.length).toBe(1)
|
|
745
|
-
expect(forSnapshot(res.data)).toMatchSnapshot()
|
|
746
|
-
})
|
|
747
|
-
|
|
748
|
-
it('filters notifications by multiple reasons', async () => {
|
|
749
|
-
const res = await agent.app.bsky.notification.listNotifications(
|
|
750
|
-
{
|
|
751
|
-
// Pin priority so the snapshot doesn't race with the viewer's stored
|
|
752
|
-
// priority preference, which neighbouring tests mutate.
|
|
753
|
-
priority: false,
|
|
754
|
-
reasons: ['mention', 'reply'],
|
|
755
|
-
},
|
|
756
|
-
{
|
|
757
|
-
headers: await network.serviceHeaders(
|
|
758
|
-
sc.dids.alice,
|
|
759
|
-
ids.AppBskyNotificationListNotifications,
|
|
760
|
-
),
|
|
761
|
-
},
|
|
762
|
-
)
|
|
763
|
-
expect(res.data.notifications.length).toBe(4)
|
|
764
|
-
expect(forSnapshot(res.data)).toMatchSnapshot()
|
|
765
|
-
})
|
|
766
|
-
|
|
767
|
-
it('paginates filtered notifications', async () => {
|
|
768
|
-
const results = (
|
|
769
|
-
results: AppBskyNotificationListNotifications.OutputSchema[],
|
|
770
|
-
) => sortNotifs(results.flatMap((res) => res.notifications))
|
|
771
|
-
const paginator = async (cursor?: string) => {
|
|
772
|
-
const res = await agent.app.bsky.notification.listNotifications(
|
|
773
|
-
{ reasons: ['mention', 'reply'], cursor, limit: 2 },
|
|
774
|
-
{
|
|
775
|
-
headers: await network.serviceHeaders(
|
|
776
|
-
alice,
|
|
777
|
-
ids.AppBskyNotificationListNotifications,
|
|
778
|
-
),
|
|
779
|
-
},
|
|
780
|
-
)
|
|
781
|
-
return res.data
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
const paginatedAll = await paginateAll(paginator)
|
|
785
|
-
paginatedAll.forEach((res) =>
|
|
786
|
-
expect(res.notifications.length).toBeLessThanOrEqual(2),
|
|
787
|
-
)
|
|
788
|
-
|
|
789
|
-
const full = await agent.app.bsky.notification.listNotifications(
|
|
790
|
-
{ reasons: ['mention', 'reply'] },
|
|
791
|
-
{
|
|
792
|
-
headers: await network.serviceHeaders(
|
|
793
|
-
alice,
|
|
794
|
-
ids.AppBskyNotificationListNotifications,
|
|
795
|
-
),
|
|
796
|
-
},
|
|
797
|
-
)
|
|
798
|
-
|
|
799
|
-
expect(full.data.notifications.length).toBe(4)
|
|
800
|
-
expect(results(paginatedAll)).toEqual(results([full.data]))
|
|
801
|
-
})
|
|
802
|
-
|
|
803
|
-
describe('handles hide tag filters', () => {
|
|
804
|
-
beforeAll(async () => {
|
|
805
|
-
const danPost = await sc.post(sc.dids.dan, 'hello friends')
|
|
806
|
-
await network.processAll()
|
|
807
|
-
const eveReply = await sc.reply(
|
|
808
|
-
sc.dids.eve,
|
|
809
|
-
danPost.ref,
|
|
810
|
-
danPost.ref,
|
|
811
|
-
'no thanks',
|
|
812
|
-
)
|
|
813
|
-
await network.processAll()
|
|
814
|
-
await createTag(db, {
|
|
815
|
-
uri: eveReply.ref.uri.toString(),
|
|
816
|
-
val: seedThreadV2.TAG_HIDE,
|
|
817
|
-
})
|
|
818
|
-
})
|
|
819
|
-
|
|
820
|
-
it('filters posts with hide tag', async () => {
|
|
821
|
-
const results = await agent.app.bsky.notification.listNotifications(
|
|
822
|
-
{ reasons: ['reply'] },
|
|
823
|
-
{
|
|
824
|
-
headers: await network.serviceHeaders(
|
|
825
|
-
dan,
|
|
826
|
-
ids.AppBskyNotificationListNotifications,
|
|
827
|
-
),
|
|
828
|
-
},
|
|
829
|
-
)
|
|
830
|
-
expect(results.data.notifications.length).toEqual(0)
|
|
831
|
-
expect(forSnapshot(results.data.notifications)).toMatchSnapshot()
|
|
832
|
-
})
|
|
833
|
-
|
|
834
|
-
it('shows posts with hide tag if they are followed', async () => {
|
|
835
|
-
await sc.follow(dan, eve)
|
|
836
|
-
await network.processAll()
|
|
837
|
-
const results = await agent.app.bsky.notification.listNotifications(
|
|
838
|
-
{ reasons: ['reply'] },
|
|
839
|
-
{
|
|
840
|
-
headers: await network.serviceHeaders(
|
|
841
|
-
dan,
|
|
842
|
-
ids.AppBskyNotificationListNotifications,
|
|
843
|
-
),
|
|
844
|
-
},
|
|
845
|
-
)
|
|
846
|
-
expect(results.data.notifications.length).toEqual(1)
|
|
847
|
-
expect(forSnapshot(results.data.notifications)).toMatchSnapshot()
|
|
848
|
-
})
|
|
849
|
-
})
|
|
850
|
-
|
|
851
|
-
describe('notifications delay', () => {
|
|
852
|
-
const notificationsDelayMs = 5_000
|
|
853
|
-
|
|
854
|
-
let delayNetwork: TestNetwork
|
|
855
|
-
let delayAgent: AtpAgent
|
|
856
|
-
let delaySc: SeedClient
|
|
857
|
-
let delayAlice: DidString
|
|
858
|
-
|
|
859
|
-
beforeAll(async () => {
|
|
860
|
-
delayNetwork = await TestNetwork.create({
|
|
861
|
-
bsky: {
|
|
862
|
-
notificationsDelayMs,
|
|
863
|
-
},
|
|
864
|
-
dbPostgresSchema: 'bsky_views_notifications_delay',
|
|
865
|
-
})
|
|
866
|
-
delayAgent = delayNetwork.bsky.getAgent()
|
|
867
|
-
delaySc = delayNetwork.getSeedClient()
|
|
868
|
-
await basicSeed(delaySc)
|
|
869
|
-
await delayNetwork.processAll()
|
|
870
|
-
delayAlice = delaySc.dids.alice
|
|
871
|
-
|
|
872
|
-
// Add to reply chain, post ancestors: alice -> bob -> alice -> carol.
|
|
873
|
-
// Should have added one notification for each of alice and bob.
|
|
874
|
-
await delaySc.reply(
|
|
875
|
-
delaySc.dids.carol,
|
|
876
|
-
delaySc.posts[delayAlice][1].ref,
|
|
877
|
-
delaySc.replies[delayAlice][0].ref,
|
|
878
|
-
'indeed',
|
|
879
|
-
)
|
|
880
|
-
await delayNetwork.processAll()
|
|
881
|
-
|
|
882
|
-
// @NOTE: Use fake timers after inserting seed data,
|
|
883
|
-
// to avoid inserting all notifications with the same timestamp.
|
|
884
|
-
vi.useFakeTimers({ toFake: ['Date'] })
|
|
885
|
-
})
|
|
886
|
-
|
|
887
|
-
afterAll(async () => {
|
|
888
|
-
vi.useRealTimers()
|
|
889
|
-
await delayNetwork.close()
|
|
890
|
-
})
|
|
891
|
-
|
|
892
|
-
it('paginates', async () => {
|
|
893
|
-
const firstNotification = await delayNetwork.bsky.db.db
|
|
894
|
-
.selectFrom('notification')
|
|
895
|
-
.selectAll()
|
|
896
|
-
.limit(1)
|
|
897
|
-
.orderBy('sortAt', 'asc')
|
|
898
|
-
.executeTakeFirstOrThrow()
|
|
899
|
-
// Sets the system time to when the first notification happened.
|
|
900
|
-
// At this point we won't have any notifications that already crossed the delay threshold.
|
|
901
|
-
vi.setSystemTime(new Date(firstNotification.sortAt))
|
|
902
|
-
|
|
903
|
-
const results = (
|
|
904
|
-
results: AppBskyNotificationListNotifications.OutputSchema[],
|
|
905
|
-
) => sortNotifs(results.flatMap((res) => res.notifications))
|
|
906
|
-
const paginator = async (cursor?: string) => {
|
|
907
|
-
const res =
|
|
908
|
-
await delayAgent.api.app.bsky.notification.listNotifications(
|
|
909
|
-
{ cursor, limit: 6 },
|
|
910
|
-
{
|
|
911
|
-
headers: await delayNetwork.serviceHeaders(
|
|
912
|
-
delayAlice,
|
|
913
|
-
ids.AppBskyNotificationListNotifications,
|
|
914
|
-
),
|
|
915
|
-
},
|
|
916
|
-
)
|
|
917
|
-
return res.data
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
const paginatedAllBeforeDelay = await paginateAll(paginator)
|
|
921
|
-
paginatedAllBeforeDelay.forEach((res) =>
|
|
922
|
-
expect(res.notifications.length).toBe(0),
|
|
923
|
-
)
|
|
924
|
-
const fullBeforeDelay =
|
|
925
|
-
await delayAgent.api.app.bsky.notification.listNotifications(
|
|
926
|
-
{},
|
|
927
|
-
{
|
|
928
|
-
headers: await delayNetwork.serviceHeaders(
|
|
929
|
-
delayAlice,
|
|
930
|
-
ids.AppBskyNotificationListNotifications,
|
|
931
|
-
),
|
|
932
|
-
},
|
|
933
|
-
)
|
|
934
|
-
|
|
935
|
-
expect(fullBeforeDelay.data.notifications.length).toEqual(0)
|
|
936
|
-
expect(results(paginatedAllBeforeDelay)).toEqual(
|
|
937
|
-
results([fullBeforeDelay.data]),
|
|
938
|
-
)
|
|
939
|
-
|
|
940
|
-
const lastNotification = await delayNetwork.bsky.db.db
|
|
941
|
-
.selectFrom('notification')
|
|
942
|
-
.selectAll()
|
|
943
|
-
.limit(1)
|
|
944
|
-
.orderBy('sortAt', 'desc')
|
|
945
|
-
.executeTakeFirstOrThrow()
|
|
946
|
-
// Sets the system time to when the last notification happened and the delay has elapsed.
|
|
947
|
-
// At this point we all notifications already crossed the delay threshold.
|
|
948
|
-
vi.setSystemTime(
|
|
949
|
-
new Date(
|
|
950
|
-
new Date(lastNotification.sortAt).getTime() +
|
|
951
|
-
notificationsDelayMs +
|
|
952
|
-
1,
|
|
953
|
-
),
|
|
954
|
-
)
|
|
955
|
-
|
|
956
|
-
const paginatedAllAfterDelay = await paginateAll(paginator)
|
|
957
|
-
paginatedAllAfterDelay.forEach((res) =>
|
|
958
|
-
expect(res.notifications.length).toBeLessThanOrEqual(6),
|
|
959
|
-
)
|
|
960
|
-
const fullAfterDelay =
|
|
961
|
-
await delayAgent.api.app.bsky.notification.listNotifications(
|
|
962
|
-
{},
|
|
963
|
-
{
|
|
964
|
-
headers: await delayNetwork.serviceHeaders(
|
|
965
|
-
delayAlice,
|
|
966
|
-
ids.AppBskyNotificationListNotifications,
|
|
967
|
-
),
|
|
968
|
-
},
|
|
969
|
-
)
|
|
970
|
-
|
|
971
|
-
expect(fullAfterDelay.data.notifications.length).toEqual(13)
|
|
972
|
-
expect(results(paginatedAllAfterDelay)).toEqual(
|
|
973
|
-
results([fullAfterDelay.data]),
|
|
974
|
-
)
|
|
975
|
-
})
|
|
976
|
-
|
|
977
|
-
describe('cursor delay', () => {
|
|
978
|
-
const delay0s = 0
|
|
979
|
-
const delay5s = 5_000
|
|
980
|
-
|
|
981
|
-
const now = '2021-01-01T01:00:00.000Z'
|
|
982
|
-
const nowMinus2s = '2021-01-01T00:59:58.000Z'
|
|
983
|
-
const nowMinus5s = '2021-01-01T00:59:55.000Z'
|
|
984
|
-
const nowMinus8s = '2021-01-01T00:59:52.000Z'
|
|
985
|
-
|
|
986
|
-
beforeAll(async () => {
|
|
987
|
-
vi.useFakeTimers({ toFake: ['Date'] })
|
|
988
|
-
vi.setSystemTime(new Date(now))
|
|
989
|
-
})
|
|
990
|
-
|
|
991
|
-
afterAll(async () => {
|
|
992
|
-
vi.useRealTimers()
|
|
993
|
-
})
|
|
994
|
-
|
|
995
|
-
describe('for undefined cursor', () => {
|
|
996
|
-
it('returns now minus delay', async () => {
|
|
997
|
-
const delayedCursor = delayCursor(undefined, delay5s)
|
|
998
|
-
expect(delayedCursor).toBe(nowMinus5s)
|
|
999
|
-
})
|
|
1000
|
-
|
|
1001
|
-
it('returns now if delay is 0', async () => {
|
|
1002
|
-
const delayedCursor = delayCursor(undefined, delay0s)
|
|
1003
|
-
expect(delayedCursor).toBe(now)
|
|
1004
|
-
})
|
|
1005
|
-
})
|
|
1006
|
-
|
|
1007
|
-
describe('for defined cursor', () => {
|
|
1008
|
-
it('returns original cursor if delay is 0', async () => {
|
|
1009
|
-
const originalCursor = nowMinus2s
|
|
1010
|
-
const delayedCursor = delayCursor(originalCursor, delay0s)
|
|
1011
|
-
expect(delayedCursor).toBe(originalCursor)
|
|
1012
|
-
})
|
|
1013
|
-
|
|
1014
|
-
it('returns "now minus delay" for cursor that is after that', async () => {
|
|
1015
|
-
// Cursor is "now - 2s", should become "now - 5s"
|
|
1016
|
-
const originalCursor = nowMinus2s
|
|
1017
|
-
const cursor = delayCursor(originalCursor, delay5s)
|
|
1018
|
-
expect(cursor).toBe(nowMinus5s)
|
|
1019
|
-
})
|
|
1020
|
-
|
|
1021
|
-
it('returns original cursor for cursor that is before "now minus delay"', async () => {
|
|
1022
|
-
// Cursor is "now - 8s", should stay like that.
|
|
1023
|
-
const originalCursor = nowMinus8s
|
|
1024
|
-
const cursor = delayCursor(originalCursor, delay5s)
|
|
1025
|
-
expect(cursor).toBe(originalCursor)
|
|
1026
|
-
})
|
|
1027
|
-
|
|
1028
|
-
it('passes through a non-date cursor', async () => {
|
|
1029
|
-
const originalCursor = '123_abc'
|
|
1030
|
-
const cursor = delayCursor(originalCursor, delay5s)
|
|
1031
|
-
expect(cursor).toBe(originalCursor)
|
|
1032
|
-
})
|
|
1033
|
-
})
|
|
1034
|
-
})
|
|
1035
|
-
})
|
|
1036
|
-
|
|
1037
|
-
describe('preferences v2', () => {
|
|
1038
|
-
beforeEach(async () => {
|
|
1039
|
-
// Drain pending bsync ops before clearing, so a stale op can't land
|
|
1040
|
-
// after the reset.
|
|
1041
|
-
await network.processAll()
|
|
1042
|
-
await clearPrivateData(db)
|
|
1043
|
-
})
|
|
1044
|
-
|
|
1045
|
-
// Defaults
|
|
1046
|
-
const fp: AppBskyNotificationDefs.FilterablePreference = {
|
|
1047
|
-
include: 'all',
|
|
1048
|
-
list: true,
|
|
1049
|
-
push: true,
|
|
1050
|
-
}
|
|
1051
|
-
const p: AppBskyNotificationDefs.Preference = {
|
|
1052
|
-
list: true,
|
|
1053
|
-
push: true,
|
|
1054
|
-
}
|
|
1055
|
-
const cp: AppBskyNotificationDefs.ChatPreference = {
|
|
1056
|
-
include: 'all',
|
|
1057
|
-
push: true,
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
it('gets preferences filling up with the defaults', async () => {
|
|
1061
|
-
const actorDid = sc.dids.carol
|
|
1062
|
-
|
|
1063
|
-
const getAndAssert = async (
|
|
1064
|
-
expectedApi: AppBskyNotificationDefs.Preferences,
|
|
1065
|
-
expectedDb: AppBskyNotificationDefs.Preferences | undefined,
|
|
1066
|
-
) => {
|
|
1067
|
-
const { data } = await agent.app.bsky.notification.getPreferences(
|
|
1068
|
-
{},
|
|
1069
|
-
{
|
|
1070
|
-
headers: await network.serviceHeaders(
|
|
1071
|
-
actorDid,
|
|
1072
|
-
ids.AppBskyNotificationGetPreferences,
|
|
1073
|
-
),
|
|
1074
|
-
},
|
|
1075
|
-
)
|
|
1076
|
-
expect(data.preferences).toStrictEqual(expectedApi)
|
|
1077
|
-
|
|
1078
|
-
const dbResult = await db.db
|
|
1079
|
-
.selectFrom('private_data')
|
|
1080
|
-
.selectAll()
|
|
1081
|
-
.where('actorDid', '=', actorDid)
|
|
1082
|
-
.where(
|
|
1083
|
-
'namespace',
|
|
1084
|
-
'=',
|
|
1085
|
-
Namespaces.AppBskyNotificationDefsPreferences.$type,
|
|
1086
|
-
)
|
|
1087
|
-
.where('key', '=', 'self')
|
|
1088
|
-
.executeTakeFirst()
|
|
1089
|
-
if (dbResult === undefined) {
|
|
1090
|
-
expect(dbResult).toBe(expectedDb)
|
|
1091
|
-
} else {
|
|
1092
|
-
expect(dbResult).toStrictEqual({
|
|
1093
|
-
actorDid: actorDid,
|
|
1094
|
-
namespace: Namespaces.AppBskyNotificationDefsPreferences.$type,
|
|
1095
|
-
key: 'self',
|
|
1096
|
-
indexedAt: expect.any(String),
|
|
1097
|
-
payload: expect.anything(), // Better to compare payload parsed.
|
|
1098
|
-
updatedAt: expect.any(String),
|
|
1099
|
-
})
|
|
1100
|
-
expect(JSON.parse(dbResult.payload)).toStrictEqual({
|
|
1101
|
-
$type: Namespaces.AppBskyNotificationDefsPreferences.$type,
|
|
1102
|
-
...expectedDb,
|
|
1103
|
-
})
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
const expectedApi0: AppBskyNotificationDefs.Preferences = {
|
|
1108
|
-
chat: cp,
|
|
1109
|
-
follow: fp,
|
|
1110
|
-
like: fp,
|
|
1111
|
-
likeViaRepost: fp,
|
|
1112
|
-
mention: fp,
|
|
1113
|
-
quote: fp,
|
|
1114
|
-
reply: fp,
|
|
1115
|
-
repost: fp,
|
|
1116
|
-
repostViaRepost: fp,
|
|
1117
|
-
starterpackJoined: p,
|
|
1118
|
-
subscribedPost: p,
|
|
1119
|
-
unverified: p,
|
|
1120
|
-
verified: p,
|
|
1121
|
-
}
|
|
1122
|
-
// The user has no preferences set yet, so nothing stored.
|
|
1123
|
-
const expectedDb0 = undefined
|
|
1124
|
-
await getAndAssert(expectedApi0, expectedDb0)
|
|
1125
|
-
|
|
1126
|
-
await agent.app.bsky.notification.putPreferencesV2(
|
|
1127
|
-
{ verified: { list: false, push: false } },
|
|
1128
|
-
{
|
|
1129
|
-
encoding: 'application/json',
|
|
1130
|
-
headers: await network.serviceHeaders(
|
|
1131
|
-
actorDid,
|
|
1132
|
-
ids.AppBskyNotificationPutPreferencesV2,
|
|
1133
|
-
),
|
|
1134
|
-
},
|
|
1135
|
-
)
|
|
1136
|
-
await network.processAll()
|
|
1137
|
-
|
|
1138
|
-
const expectedApi1: AppBskyNotificationDefs.Preferences = {
|
|
1139
|
-
chat: cp,
|
|
1140
|
-
follow: fp,
|
|
1141
|
-
like: fp,
|
|
1142
|
-
likeViaRepost: fp,
|
|
1143
|
-
mention: fp,
|
|
1144
|
-
quote: fp,
|
|
1145
|
-
reply: fp,
|
|
1146
|
-
repost: fp,
|
|
1147
|
-
repostViaRepost: fp,
|
|
1148
|
-
starterpackJoined: p,
|
|
1149
|
-
subscribedPost: p,
|
|
1150
|
-
unverified: p,
|
|
1151
|
-
verified: { list: false, push: false },
|
|
1152
|
-
}
|
|
1153
|
-
// Stored all the defaults.
|
|
1154
|
-
const expectedDb1 = expectedApi1
|
|
1155
|
-
await getAndAssert(expectedApi1, expectedDb1)
|
|
1156
|
-
})
|
|
1157
|
-
|
|
1158
|
-
it('stores the preferences setting the defaults', async () => {
|
|
1159
|
-
const actorDid = sc.dids.carol
|
|
1160
|
-
|
|
1161
|
-
const putAndAssert = async (
|
|
1162
|
-
input: AppBskyNotificationPutPreferencesV2.InputSchema,
|
|
1163
|
-
expected: AppBskyNotificationDefs.Preferences,
|
|
1164
|
-
) => {
|
|
1165
|
-
const { data } = await agent.app.bsky.notification.putPreferencesV2(
|
|
1166
|
-
input,
|
|
1167
|
-
{
|
|
1168
|
-
encoding: 'application/json',
|
|
1169
|
-
headers: await network.serviceHeaders(
|
|
1170
|
-
actorDid,
|
|
1171
|
-
'app.bsky.notification.putPreferencesV2',
|
|
1172
|
-
),
|
|
1173
|
-
},
|
|
1174
|
-
)
|
|
1175
|
-
await network.processAll()
|
|
1176
|
-
expect(data.preferences).toStrictEqual(expected)
|
|
1177
|
-
|
|
1178
|
-
const dbResult = await db.db
|
|
1179
|
-
.selectFrom('private_data')
|
|
1180
|
-
.selectAll()
|
|
1181
|
-
.where('actorDid', '=', actorDid)
|
|
1182
|
-
.where(
|
|
1183
|
-
'namespace',
|
|
1184
|
-
'=',
|
|
1185
|
-
Namespaces.AppBskyNotificationDefsPreferences.$type,
|
|
1186
|
-
)
|
|
1187
|
-
.where('key', '=', 'self')
|
|
1188
|
-
.executeTakeFirstOrThrow()
|
|
1189
|
-
expect(dbResult).toStrictEqual({
|
|
1190
|
-
actorDid: actorDid,
|
|
1191
|
-
namespace: Namespaces.AppBskyNotificationDefsPreferences.$type,
|
|
1192
|
-
key: 'self',
|
|
1193
|
-
indexedAt: expect.any(String),
|
|
1194
|
-
payload: expect.anything(), // Better to compare payload parsed.
|
|
1195
|
-
updatedAt: expect.any(String),
|
|
1196
|
-
})
|
|
1197
|
-
expect(JSON.parse(dbResult.payload)).toStrictEqual({
|
|
1198
|
-
...expected,
|
|
1199
|
-
$type: Namespaces.AppBskyNotificationDefsPreferences.$type,
|
|
1200
|
-
})
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
const input0 = {
|
|
1204
|
-
chat: {
|
|
1205
|
-
push: false,
|
|
1206
|
-
include: 'accepted',
|
|
1207
|
-
},
|
|
1208
|
-
}
|
|
1209
|
-
const expected0: AppBskyNotificationDefs.Preferences = {
|
|
1210
|
-
// chat is deprecated: input is ignored and the default is always returned.
|
|
1211
|
-
chat: cp,
|
|
1212
|
-
follow: fp,
|
|
1213
|
-
like: fp,
|
|
1214
|
-
likeViaRepost: fp,
|
|
1215
|
-
mention: fp,
|
|
1216
|
-
quote: fp,
|
|
1217
|
-
reply: fp,
|
|
1218
|
-
repost: fp,
|
|
1219
|
-
repostViaRepost: fp,
|
|
1220
|
-
starterpackJoined: p,
|
|
1221
|
-
subscribedPost: p,
|
|
1222
|
-
unverified: p,
|
|
1223
|
-
verified: p,
|
|
1224
|
-
}
|
|
1225
|
-
await putAndAssert(input0, expected0)
|
|
1226
|
-
|
|
1227
|
-
const input1 = {
|
|
1228
|
-
mention: {
|
|
1229
|
-
list: false,
|
|
1230
|
-
push: false,
|
|
1231
|
-
include: 'follows',
|
|
1232
|
-
},
|
|
1233
|
-
}
|
|
1234
|
-
const expected1: AppBskyNotificationDefs.Preferences = {
|
|
1235
|
-
// chat is deprecated: input is ignored and the default is always returned.
|
|
1236
|
-
chat: cp,
|
|
1237
|
-
follow: fp,
|
|
1238
|
-
like: fp,
|
|
1239
|
-
likeViaRepost: fp,
|
|
1240
|
-
mention: input1.mention,
|
|
1241
|
-
quote: fp,
|
|
1242
|
-
reply: fp,
|
|
1243
|
-
repost: fp,
|
|
1244
|
-
repostViaRepost: fp,
|
|
1245
|
-
starterpackJoined: p,
|
|
1246
|
-
subscribedPost: p,
|
|
1247
|
-
unverified: p,
|
|
1248
|
-
verified: p,
|
|
1249
|
-
}
|
|
1250
|
-
await putAndAssert(input1, expected1)
|
|
1251
|
-
})
|
|
1252
|
-
})
|
|
1253
|
-
|
|
1254
|
-
describe('activity subscriptions', () => {
|
|
1255
|
-
const sortProfiles = (profiles: AppBskyActorDefs.ProfileView[]) => {
|
|
1256
|
-
return profiles.sort((a, b) => (a.handle > b.handle ? 1 : -1))
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
const declare = async (actor: DidString, value: string) => {
|
|
1260
|
-
await pdsAgent.com.atproto.repo.createRecord(
|
|
1261
|
-
{
|
|
1262
|
-
repo: actor,
|
|
1263
|
-
collection: ids.AppBskyNotificationDeclaration,
|
|
1264
|
-
rkey: 'self',
|
|
1265
|
-
record: {
|
|
1266
|
-
allowSubscriptions: value,
|
|
1267
|
-
} as AppBskyNotificationDeclaration.Record,
|
|
1268
|
-
},
|
|
1269
|
-
{ headers: sc.getHeaders(actor), encoding: 'application/json' },
|
|
1270
|
-
)
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
const put = async (
|
|
1274
|
-
actor: DidString,
|
|
1275
|
-
subject: DidString,
|
|
1276
|
-
val: AppBskyNotificationDefs.ActivitySubscription,
|
|
1277
|
-
) =>
|
|
1278
|
-
agent.app.bsky.notification.putActivitySubscription(
|
|
1279
|
-
{
|
|
1280
|
-
subject,
|
|
1281
|
-
activitySubscription: val,
|
|
1282
|
-
},
|
|
1283
|
-
{
|
|
1284
|
-
headers: await network.serviceHeaders(
|
|
1285
|
-
actor,
|
|
1286
|
-
'app.bsky.notification.putActivitySubscription',
|
|
1287
|
-
),
|
|
1288
|
-
},
|
|
1289
|
-
)
|
|
1290
|
-
|
|
1291
|
-
const list = async (
|
|
1292
|
-
actor: DidString,
|
|
1293
|
-
params?: AppBskyNotificationListActivitySubscriptions.QueryParams,
|
|
1294
|
-
) =>
|
|
1295
|
-
agent.app.bsky.notification.listActivitySubscriptions(params ?? {}, {
|
|
1296
|
-
headers: await network.serviceHeaders(
|
|
1297
|
-
actor,
|
|
1298
|
-
ids.AppBskyNotificationListActivitySubscriptions,
|
|
1299
|
-
),
|
|
1300
|
-
})
|
|
1301
|
-
|
|
1302
|
-
const associatedAllowSub = async (actor: string, subject: string) => {
|
|
1303
|
-
const { data } = await agent.app.bsky.actor.getProfile(
|
|
1304
|
-
{ actor: subject },
|
|
1305
|
-
{
|
|
1306
|
-
headers: await network.serviceHeaders(
|
|
1307
|
-
actor,
|
|
1308
|
-
ids.AppBskyActorGetProfile,
|
|
1309
|
-
),
|
|
1310
|
-
},
|
|
1311
|
-
)
|
|
1312
|
-
return data.associated?.activitySubscription?.allowSubscriptions
|
|
1313
|
-
}
|
|
1314
|
-
|
|
1315
|
-
const viewerActivitySub = async (actor: string, subject: string) => {
|
|
1316
|
-
const { data } = await agent.app.bsky.actor.getProfile(
|
|
1317
|
-
{ actor: subject },
|
|
1318
|
-
{
|
|
1319
|
-
headers: await network.serviceHeaders(
|
|
1320
|
-
actor,
|
|
1321
|
-
ids.AppBskyActorGetProfile,
|
|
1322
|
-
),
|
|
1323
|
-
},
|
|
1324
|
-
)
|
|
1325
|
-
return data.viewer?.activitySubscription
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
beforeAll(async () => {
|
|
1329
|
-
// 'none' declaration.
|
|
1330
|
-
await declare(bob, 'none')
|
|
1331
|
-
|
|
1332
|
-
// 'mutuals' declaration and both follow.
|
|
1333
|
-
await declare(carol, 'mutuals')
|
|
1334
|
-
await sc.follow(alice, carol)
|
|
1335
|
-
await sc.follow(carol, alice)
|
|
1336
|
-
|
|
1337
|
-
// 'mutuals' declaration but only actor follows.
|
|
1338
|
-
await declare(dan, 'mutuals')
|
|
1339
|
-
await sc.follow(alice, dan)
|
|
1340
|
-
|
|
1341
|
-
// 'mutuals' declaration but only subject follows.
|
|
1342
|
-
await declare(eve, 'mutuals')
|
|
1343
|
-
await sc.follow(eve, alice)
|
|
1344
|
-
|
|
1345
|
-
// 'followers' declaration and viewer follows.
|
|
1346
|
-
await declare(fred, 'followers')
|
|
1347
|
-
await sc.follow(alice, fred)
|
|
1348
|
-
|
|
1349
|
-
// 'followers' declaration but viewer does not follow.
|
|
1350
|
-
await declare(greg, 'followers')
|
|
1351
|
-
|
|
1352
|
-
// blocked.
|
|
1353
|
-
await declare(blocked, 'followers')
|
|
1354
|
-
await sc.block(alice, blocked)
|
|
1355
|
-
|
|
1356
|
-
await network.processAll()
|
|
1357
|
-
})
|
|
1358
|
-
|
|
1359
|
-
beforeEach(async () => {
|
|
1360
|
-
// Drain pending bsync ops before clearing, so a stale op can't land
|
|
1361
|
-
// after the reset.
|
|
1362
|
-
await network.processAll()
|
|
1363
|
-
await clearActivitySubscription(db)
|
|
1364
|
-
})
|
|
1365
|
-
|
|
1366
|
-
it('lists an empty list of subscriptions', async () => {
|
|
1367
|
-
const actorDid = alice
|
|
1368
|
-
|
|
1369
|
-
const { data } = await list(actorDid)
|
|
1370
|
-
|
|
1371
|
-
expect(data.cursor).toBeUndefined()
|
|
1372
|
-
expect(data.subscriptions).toHaveLength(0)
|
|
1373
|
-
})
|
|
1374
|
-
|
|
1375
|
-
it('does not allow subscribing to self', async () => {
|
|
1376
|
-
const actorDid = alice
|
|
1377
|
-
const promise = put(actorDid, actorDid, { post: true, reply: false })
|
|
1378
|
-
|
|
1379
|
-
await expect(promise).rejects.toThrow('Cannot subscribe to own activity')
|
|
1380
|
-
})
|
|
1381
|
-
|
|
1382
|
-
it('inserts a subscription entry if it does not exist', async () => {
|
|
1383
|
-
const actorDid = alice
|
|
1384
|
-
const subjectDid = fred
|
|
1385
|
-
const val = { post: true, reply: false }
|
|
1386
|
-
|
|
1387
|
-
const { data: createData } = await put(actorDid, subjectDid, val)
|
|
1388
|
-
expect(createData).toStrictEqual({
|
|
1389
|
-
subject: subjectDid,
|
|
1390
|
-
activitySubscription: val,
|
|
1391
|
-
})
|
|
1392
|
-
await network.processAll()
|
|
1393
|
-
|
|
1394
|
-
const { data: listData } = await list(actorDid)
|
|
1395
|
-
expect(listData).toEqual({
|
|
1396
|
-
cursor: expect.any(String),
|
|
1397
|
-
subscriptions: [
|
|
1398
|
-
expect.objectContaining({
|
|
1399
|
-
did: subjectDid,
|
|
1400
|
-
viewer: expect.objectContaining({ activitySubscription: val }),
|
|
1401
|
-
}),
|
|
1402
|
-
],
|
|
1403
|
-
})
|
|
1404
|
-
})
|
|
1405
|
-
|
|
1406
|
-
it('updates a subscription entry if it exists', async () => {
|
|
1407
|
-
const actorDid = alice
|
|
1408
|
-
const subjectDid = fred
|
|
1409
|
-
const valCreate = { post: true, reply: false }
|
|
1410
|
-
const valUpdate = { post: false, reply: true }
|
|
1411
|
-
|
|
1412
|
-
const { data: createData } = await put(actorDid, subjectDid, valCreate)
|
|
1413
|
-
expect(createData).toStrictEqual({
|
|
1414
|
-
subject: subjectDid,
|
|
1415
|
-
activitySubscription: valCreate,
|
|
1416
|
-
})
|
|
1417
|
-
|
|
1418
|
-
const { data: updateData } = await put(actorDid, subjectDid, valUpdate)
|
|
1419
|
-
expect(updateData).toStrictEqual({
|
|
1420
|
-
subject: subjectDid,
|
|
1421
|
-
activitySubscription: valUpdate,
|
|
1422
|
-
})
|
|
1423
|
-
await network.processAll()
|
|
1424
|
-
|
|
1425
|
-
const { data: listData } = await list(actorDid)
|
|
1426
|
-
expect(listData).toEqual({
|
|
1427
|
-
cursor: expect.any(String),
|
|
1428
|
-
subscriptions: [
|
|
1429
|
-
expect.objectContaining({
|
|
1430
|
-
did: subjectDid,
|
|
1431
|
-
viewer: expect.objectContaining({
|
|
1432
|
-
activitySubscription: valUpdate,
|
|
1433
|
-
}),
|
|
1434
|
-
}),
|
|
1435
|
-
],
|
|
1436
|
-
})
|
|
1437
|
-
})
|
|
1438
|
-
|
|
1439
|
-
it('deletes a subscription entry when all options are turned off', async () => {
|
|
1440
|
-
const actorDid = alice
|
|
1441
|
-
const subjectDid = fred
|
|
1442
|
-
const valCreate = { post: true, reply: false }
|
|
1443
|
-
const valDelete = { post: false, reply: false }
|
|
1444
|
-
|
|
1445
|
-
await put(actorDid, subjectDid, valCreate)
|
|
1446
|
-
await network.processAll()
|
|
1447
|
-
const { data: list0 } = await list(actorDid)
|
|
1448
|
-
expect(list0.subscriptions).toHaveLength(1)
|
|
1449
|
-
|
|
1450
|
-
await put(actorDid, subjectDid, valDelete)
|
|
1451
|
-
await network.processAll()
|
|
1452
|
-
const { data: list1 } = await list(actorDid)
|
|
1453
|
-
expect(list1.subscriptions).toHaveLength(0)
|
|
1454
|
-
})
|
|
1455
|
-
|
|
1456
|
-
it('paginates', async () => {
|
|
1457
|
-
const actorDid = alice
|
|
1458
|
-
const limit = 2
|
|
1459
|
-
const val = { post: true, reply: false }
|
|
1460
|
-
|
|
1461
|
-
await put(actorDid, bob, val)
|
|
1462
|
-
await put(actorDid, carol, val)
|
|
1463
|
-
await put(actorDid, dan, val)
|
|
1464
|
-
await put(actorDid, eve, val)
|
|
1465
|
-
await put(actorDid, fred, val)
|
|
1466
|
-
await put(actorDid, blocked, val) // blocked is removed from the list.
|
|
1467
|
-
await network.processAll()
|
|
1468
|
-
|
|
1469
|
-
const results = (
|
|
1470
|
-
results: AppBskyNotificationListActivitySubscriptions.OutputSchema[],
|
|
1471
|
-
) =>
|
|
1472
|
-
sortProfiles(
|
|
1473
|
-
results.flatMap(
|
|
1474
|
-
(res: AppBskyNotificationListActivitySubscriptions.OutputSchema) =>
|
|
1475
|
-
res.subscriptions,
|
|
1476
|
-
),
|
|
1477
|
-
)
|
|
1478
|
-
const paginator = async (cursor?: string) => {
|
|
1479
|
-
const { data } = await list(actorDid, { cursor, limit })
|
|
1480
|
-
return data
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
|
-
const paginatedAll = await paginateAll(paginator)
|
|
1484
|
-
paginatedAll.forEach((res) =>
|
|
1485
|
-
expect(res.subscriptions.length).toBeLessThanOrEqual(limit),
|
|
1486
|
-
)
|
|
1487
|
-
|
|
1488
|
-
const full = await list(actorDid)
|
|
1489
|
-
expect(full.data.subscriptions.length).toEqual(5)
|
|
1490
|
-
expect(results(paginatedAll)).toEqual(results([full.data]))
|
|
1491
|
-
})
|
|
1492
|
-
|
|
1493
|
-
it('gets the declaration record', async () => {
|
|
1494
|
-
const declaration = await pdsAgent.com.atproto.repo.getRecord({
|
|
1495
|
-
repo: carol,
|
|
1496
|
-
collection: 'app.bsky.notification.declaration',
|
|
1497
|
-
rkey: 'self',
|
|
1498
|
-
})
|
|
1499
|
-
|
|
1500
|
-
expect(declaration.data.value.allowSubscriptions).toEqual('mutuals')
|
|
1501
|
-
})
|
|
1502
|
-
|
|
1503
|
-
describe('activity subscription declaration', () => {
|
|
1504
|
-
it('includes the declaration in the profile view', async () => {
|
|
1505
|
-
await expect(associatedAllowSub(alice, bob)).resolves.toBe('none')
|
|
1506
|
-
await expect(associatedAllowSub(alice, carol)).resolves.toBe('mutuals')
|
|
1507
|
-
await expect(associatedAllowSub(alice, dan)).resolves.toBe('mutuals')
|
|
1508
|
-
await expect(associatedAllowSub(alice, eve)).resolves.toBe('mutuals')
|
|
1509
|
-
await expect(associatedAllowSub(alice, fred)).resolves.toBe('followers')
|
|
1510
|
-
await expect(associatedAllowSub(alice, greg)).resolves.toBe('followers')
|
|
1511
|
-
})
|
|
1512
|
-
})
|
|
1513
|
-
|
|
1514
|
-
describe('activity subscription viewer state', () => {
|
|
1515
|
-
it('includes the relationship in the profile view', async () => {
|
|
1516
|
-
const viewer = alice
|
|
1517
|
-
const val = { post: true, reply: true }
|
|
1518
|
-
|
|
1519
|
-
// 'none' declaration.
|
|
1520
|
-
await put(viewer, bob, val)
|
|
1521
|
-
await network.processAll()
|
|
1522
|
-
await expect(viewerActivitySub(viewer, bob)).resolves.toBeUndefined()
|
|
1523
|
-
|
|
1524
|
-
// 'mutuals' declaration and both follow.
|
|
1525
|
-
await put(viewer, carol, val)
|
|
1526
|
-
await network.processAll()
|
|
1527
|
-
await expect(viewerActivitySub(viewer, carol)).resolves.toStrictEqual(
|
|
1528
|
-
val,
|
|
1529
|
-
)
|
|
1530
|
-
|
|
1531
|
-
// 'mutuals' declaration but only actor follows.
|
|
1532
|
-
await put(viewer, dan, val)
|
|
1533
|
-
await network.processAll()
|
|
1534
|
-
await expect(viewerActivitySub(viewer, dan)).resolves.toBeUndefined()
|
|
1535
|
-
|
|
1536
|
-
// 'mutuals' declaration but only subject follows.
|
|
1537
|
-
await put(viewer, eve, val)
|
|
1538
|
-
await network.processAll()
|
|
1539
|
-
await expect(viewerActivitySub(viewer, eve)).resolves.toBeUndefined()
|
|
1540
|
-
|
|
1541
|
-
// 'followers' declaration and viewer follows.
|
|
1542
|
-
await put(viewer, fred, val)
|
|
1543
|
-
await network.processAll()
|
|
1544
|
-
await expect(viewerActivitySub(viewer, carol)).resolves.toStrictEqual(
|
|
1545
|
-
val,
|
|
1546
|
-
)
|
|
1547
|
-
|
|
1548
|
-
// 'followers' declaration but viewer does not follow.
|
|
1549
|
-
await expect(viewerActivitySub(viewer, greg)).resolves.toBeUndefined()
|
|
1550
|
-
|
|
1551
|
-
// no declaration
|
|
1552
|
-
await expect(viewerActivitySub(viewer, han)).resolves.toBeUndefined()
|
|
1553
|
-
})
|
|
1554
|
-
})
|
|
1555
|
-
})
|
|
1556
|
-
})
|
|
1557
|
-
|
|
1558
|
-
const clearPrivateData = async (db: Database) => {
|
|
1559
|
-
await db.db.deleteFrom('private_data').execute()
|
|
1560
|
-
}
|
|
1561
|
-
|
|
1562
|
-
const clearActivitySubscription = async (db: Database) => {
|
|
1563
|
-
await db.db.deleteFrom('activity_subscription').execute()
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
const createTag = async (
|
|
1567
|
-
db: Database,
|
|
1568
|
-
opts: {
|
|
1569
|
-
uri: string
|
|
1570
|
-
val: string
|
|
1571
|
-
},
|
|
1572
|
-
) => {
|
|
1573
|
-
await db.db
|
|
1574
|
-
.updateTable('record')
|
|
1575
|
-
.set({
|
|
1576
|
-
tags: JSON.stringify([opts.val]),
|
|
1577
|
-
})
|
|
1578
|
-
.where('uri', '=', opts.uri)
|
|
1579
|
-
.returningAll()
|
|
1580
|
-
.execute()
|
|
1581
|
-
}
|