From 29d2de762265f2cf63c044bd00838295bb37b40c Mon Sep 17 00:00:00 2001 From: dholms Date: Wed, 6 Dec 2023 15:26:39 -0600 Subject: [PATCH 01/83] early sketchwork --- packages/bsky/proto/bsky.proto | 12 +-- .../bsky/src/data-plane/gen/bsky_connect.ts | 12 +-- packages/bsky/src/data-plane/gen/bsky_pb.ts | 66 ++++++++-------- packages/bsky/src/hydration/actor.ts | 49 ++++++++++++ packages/bsky/src/hydration/graph.ts | 68 ++++++++++++++++ packages/bsky/src/hydration/hydrator.ts | 77 +++++++++++++++++++ packages/bsky/src/views/lists.ts | 44 +++++++++++ 7 files changed, 283 insertions(+), 45 deletions(-) create mode 100644 packages/bsky/src/hydration/actor.ts create mode 100644 packages/bsky/src/hydration/graph.ts create mode 100644 packages/bsky/src/hydration/hydrator.ts create mode 100644 packages/bsky/src/views/lists.ts diff --git a/packages/bsky/proto/bsky.proto b/packages/bsky/proto/bsky.proto index ad273562773..f4a0f2cbb1a 100644 --- a/packages/bsky/proto/bsky.proto +++ b/packages/bsky/proto/bsky.proto @@ -238,12 +238,12 @@ message GetListMembershipResponse { // - Return list record for list uri // - list view hydration -message GetListRequest { - string list_uri = 1; +message GetListsRequest { + repeated string uris = 1; } -message GetListResponse { - bytes record = 1; +message GetListsResponse { + repeated bytes records = 1; } // - Return number of items in list A @@ -377,7 +377,7 @@ message GetBlocklistSubscriptionRequest { } message GetBlocklistSubscriptionResponse { - bool subscribed = 1; + string listblock_uri = 1; } // - return list of list uris of Blockslists that A subscribes to @@ -724,7 +724,7 @@ service Service { // Lists rpc GetListMembers(GetListMembersRequest) returns (GetListMembersResponse); rpc GetListMembership(GetListMembershipRequest) returns (GetListMembershipResponse); - rpc GetList(GetListRequest) returns (GetListResponse); + rpc GetLists(GetListsRequest) returns (GetListsResponse); rpc GetListCount(GetListCountRequest) returns (GetListCountResponse); // Mutes diff --git a/packages/bsky/src/data-plane/gen/bsky_connect.ts b/packages/bsky/src/data-plane/gen/bsky_connect.ts index 482f0c061ac..c9e39b97edb 100644 --- a/packages/bsky/src/data-plane/gen/bsky_connect.ts +++ b/packages/bsky/src/data-plane/gen/bsky_connect.ts @@ -3,7 +3,7 @@ /* eslint-disable */ // @ts-nocheck -import { GetActorFeedsRequest, GetActorFeedsResponse, GetActorFollowsActorsRequest, GetActorFollowsActorsResponse, GetActorLikesRequest, GetActorLikesResponse, GetActorMutesActorRequest, GetActorMutesActorResponse, GetActorMutesActorViaListRequest, GetActorMutesActorViaListResponse, GetActorRepostsRequest, GetActorRepostsResponse, GetAuthorFeedRequest, GetAuthorFeedResponse, GetBidirectionalBlockRequest, GetBidirectionalBlockResponse, GetBidirectionalBlockViaListRequest, GetBidirectionalBlockViaListResponse, GetBlobTakedownRequest, GetBlobTakedownResponse, GetBlocklistSubscriptionRequest, GetBlocklistSubscriptionResponse, GetBlocklistSubscriptionsRequest, GetBlocklistSubscriptionsResponse, GetBlocksRequest, GetBlocksResponse, GetDidsByHandlesRequest, GetDidsByHandlesResponse, GetFeedGeneratorsRequest, GetFeedGeneratorsResponse, GetFeedGeneratorStatusRequest, GetFeedGeneratorStatusResponse, GetFollowersCountRequest, GetFollowersCountResponse, GetFollowersRequest, GetFollowersResponse, GetFollowsCountRequest, GetFollowsCountResponse, GetFollowsRequest, GetFollowsResponse, GetHandlesRequest, GetHandlesResponse, GetLabelsRequest, GetLabelsResponse, GetLatestRevRequest, GetLatestRevResponse, GetLikeByActorAndSubjectRequest, GetLikeByActorAndSubjectResponse, GetLikesBySubjectRequest, GetLikesBySubjectResponse, GetLikesCountRequest, GetLikesCountResponse, GetListCountRequest, GetListCountResponse, GetListFeedRequest, GetListFeedResponse, GetListMembershipRequest, GetListMembershipResponse, GetListMembersRequest, GetListMembersResponse, GetListRequest, GetListResponse, GetMutelistSubscriptionRequest, GetMutelistSubscriptionResponse, GetMutelistSubscriptionsRequest, GetMutelistSubscriptionsResponse, GetMutesRequest, GetMutesResponse, GetNotificationSeenRequest, GetNotificationSeenResponse, GetNotificationsRequest, GetNotificationsResponse, GetPostReplyCountRequest, GetPostReplyCountResponse, GetPostsRequest, GetPostsResponse, GetProfilesRequest, GetProfilesResponse, GetRepostByActorAndSubjectRequest, GetRepostByActorAndSubjectResponse, GetRepostsBySubjectRequest, GetRepostsBySubjectResponse, GetRepostsCountRequest, GetRepostsCountResponse, GetSuggestedFeedsRequest, GetSuggestedFeedsResponse, GetSuggestionsRequest, GetSuggestionsResponse, GetThreadgatesRequest, GetThreadgatesResponse, GetThreadRequest, GetThreadResponse, GetTimelineRequest, GetTimelineResponse, GetUnreadNotificationCountRequest, GetUnreadNotificationCountResponse, PingRequest, PingResponse, SearchActorsRequest, SearchActorsResponse, SearchPostsRequest, SearchPostsResponse, UpdateNotificationSeenRequest, UpdateNotificationSeenResponse, UpdateTakedownRequest, UpdateTakedownResponse } from "./bsky_pb"; +import { GetActorFeedsRequest, GetActorFeedsResponse, GetActorFollowsActorsRequest, GetActorFollowsActorsResponse, GetActorLikesRequest, GetActorLikesResponse, GetActorMutesActorRequest, GetActorMutesActorResponse, GetActorMutesActorViaListRequest, GetActorMutesActorViaListResponse, GetActorRepostsRequest, GetActorRepostsResponse, GetAuthorFeedRequest, GetAuthorFeedResponse, GetBidirectionalBlockRequest, GetBidirectionalBlockResponse, GetBidirectionalBlockViaListRequest, GetBidirectionalBlockViaListResponse, GetBlobTakedownRequest, GetBlobTakedownResponse, GetBlocklistSubscriptionRequest, GetBlocklistSubscriptionResponse, GetBlocklistSubscriptionsRequest, GetBlocklistSubscriptionsResponse, GetBlocksRequest, GetBlocksResponse, GetDidsByHandlesRequest, GetDidsByHandlesResponse, GetFeedGeneratorsRequest, GetFeedGeneratorsResponse, GetFeedGeneratorStatusRequest, GetFeedGeneratorStatusResponse, GetFollowersCountRequest, GetFollowersCountResponse, GetFollowersRequest, GetFollowersResponse, GetFollowsCountRequest, GetFollowsCountResponse, GetFollowsRequest, GetFollowsResponse, GetHandlesRequest, GetHandlesResponse, GetLabelsRequest, GetLabelsResponse, GetLatestRevRequest, GetLatestRevResponse, GetLikeByActorAndSubjectRequest, GetLikeByActorAndSubjectResponse, GetLikesBySubjectRequest, GetLikesBySubjectResponse, GetLikesCountRequest, GetLikesCountResponse, GetListCountRequest, GetListCountResponse, GetListFeedRequest, GetListFeedResponse, GetListMembershipRequest, GetListMembershipResponse, GetListMembersRequest, GetListMembersResponse, GetListsRequest, GetListsResponse, GetMutelistSubscriptionRequest, GetMutelistSubscriptionResponse, GetMutelistSubscriptionsRequest, GetMutelistSubscriptionsResponse, GetMutesRequest, GetMutesResponse, GetNotificationSeenRequest, GetNotificationSeenResponse, GetNotificationsRequest, GetNotificationsResponse, GetPostReplyCountRequest, GetPostReplyCountResponse, GetPostsRequest, GetPostsResponse, GetProfilesRequest, GetProfilesResponse, GetRepostByActorAndSubjectRequest, GetRepostByActorAndSubjectResponse, GetRepostsBySubjectRequest, GetRepostsBySubjectResponse, GetRepostsCountRequest, GetRepostsCountResponse, GetSuggestedFeedsRequest, GetSuggestedFeedsResponse, GetSuggestionsRequest, GetSuggestionsResponse, GetThreadgatesRequest, GetThreadgatesResponse, GetThreadRequest, GetThreadResponse, GetTimelineRequest, GetTimelineResponse, GetUnreadNotificationCountRequest, GetUnreadNotificationCountResponse, PingRequest, PingResponse, SearchActorsRequest, SearchActorsResponse, SearchPostsRequest, SearchPostsResponse, UpdateNotificationSeenRequest, UpdateNotificationSeenResponse, UpdateTakedownRequest, UpdateTakedownResponse } from "./bsky_pb.js"; import { MethodKind } from "@bufbuild/protobuf"; /** @@ -185,12 +185,12 @@ export const Service = { kind: MethodKind.Unary, }, /** - * @generated from rpc bsky.Service.GetList + * @generated from rpc bsky.Service.GetLists */ - getList: { - name: "GetList", - I: GetListRequest, - O: GetListResponse, + getLists: { + name: "GetLists", + I: GetListsRequest, + O: GetListsResponse, kind: MethodKind.Unary, }, /** diff --git a/packages/bsky/src/data-plane/gen/bsky_pb.ts b/packages/bsky/src/data-plane/gen/bsky_pb.ts index 600086aa596..81ae3b65243 100644 --- a/packages/bsky/src/data-plane/gen/bsky_pb.ts +++ b/packages/bsky/src/data-plane/gen/bsky_pb.ts @@ -1548,76 +1548,76 @@ export class GetListMembershipResponse extends Message { +export class GetListsRequest extends Message { /** - * @generated from field: string list_uri = 1; + * @generated from field: repeated string uris = 1; */ - listUri = ""; + uris: string[] = []; - constructor(data?: PartialMessage) { + constructor(data?: PartialMessage) { super(); proto3.util.initPartial(data, this); } static readonly runtime: typeof proto3 = proto3; - static readonly typeName = "bsky.GetListRequest"; + static readonly typeName = "bsky.GetListsRequest"; static readonly fields: FieldList = proto3.util.newFieldList(() => [ - { no: 1, name: "list_uri", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 1, name: "uris", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, ]); - static fromBinary(bytes: Uint8Array, options?: Partial): GetListRequest { - return new GetListRequest().fromBinary(bytes, options); + static fromBinary(bytes: Uint8Array, options?: Partial): GetListsRequest { + return new GetListsRequest().fromBinary(bytes, options); } - static fromJson(jsonValue: JsonValue, options?: Partial): GetListRequest { - return new GetListRequest().fromJson(jsonValue, options); + static fromJson(jsonValue: JsonValue, options?: Partial): GetListsRequest { + return new GetListsRequest().fromJson(jsonValue, options); } - static fromJsonString(jsonString: string, options?: Partial): GetListRequest { - return new GetListRequest().fromJsonString(jsonString, options); + static fromJsonString(jsonString: string, options?: Partial): GetListsRequest { + return new GetListsRequest().fromJsonString(jsonString, options); } - static equals(a: GetListRequest | PlainMessage | undefined, b: GetListRequest | PlainMessage | undefined): boolean { - return proto3.util.equals(GetListRequest, a, b); + static equals(a: GetListsRequest | PlainMessage | undefined, b: GetListsRequest | PlainMessage | undefined): boolean { + return proto3.util.equals(GetListsRequest, a, b); } } /** - * @generated from message bsky.GetListResponse + * @generated from message bsky.GetListsResponse */ -export class GetListResponse extends Message { +export class GetListsResponse extends Message { /** - * @generated from field: bytes record = 1; + * @generated from field: repeated bytes records = 1; */ - record = new Uint8Array(0); + records: Uint8Array[] = []; - constructor(data?: PartialMessage) { + constructor(data?: PartialMessage) { super(); proto3.util.initPartial(data, this); } static readonly runtime: typeof proto3 = proto3; - static readonly typeName = "bsky.GetListResponse"; + static readonly typeName = "bsky.GetListsResponse"; static readonly fields: FieldList = proto3.util.newFieldList(() => [ - { no: 1, name: "record", kind: "scalar", T: 12 /* ScalarType.BYTES */ }, + { no: 1, name: "records", kind: "scalar", T: 12 /* ScalarType.BYTES */, repeated: true }, ]); - static fromBinary(bytes: Uint8Array, options?: Partial): GetListResponse { - return new GetListResponse().fromBinary(bytes, options); + static fromBinary(bytes: Uint8Array, options?: Partial): GetListsResponse { + return new GetListsResponse().fromBinary(bytes, options); } - static fromJson(jsonValue: JsonValue, options?: Partial): GetListResponse { - return new GetListResponse().fromJson(jsonValue, options); + static fromJson(jsonValue: JsonValue, options?: Partial): GetListsResponse { + return new GetListsResponse().fromJson(jsonValue, options); } - static fromJsonString(jsonString: string, options?: Partial): GetListResponse { - return new GetListResponse().fromJsonString(jsonString, options); + static fromJsonString(jsonString: string, options?: Partial): GetListsResponse { + return new GetListsResponse().fromJsonString(jsonString, options); } - static equals(a: GetListResponse | PlainMessage | undefined, b: GetListResponse | PlainMessage | undefined): boolean { - return proto3.util.equals(GetListResponse, a, b); + static equals(a: GetListsResponse | PlainMessage | undefined, b: GetListsResponse | PlainMessage | undefined): boolean { + return proto3.util.equals(GetListsResponse, a, b); } } @@ -2452,9 +2452,9 @@ export class GetBlocklistSubscriptionRequest extends Message { /** - * @generated from field: bool subscribed = 1; + * @generated from field: string listblock_uri = 1; */ - subscribed = false; + listblockUri = ""; constructor(data?: PartialMessage) { super(); @@ -2464,7 +2464,7 @@ export class GetBlocklistSubscriptionResponse extends Message [ - { no: 1, name: "subscribed", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + { no: 1, name: "listblock_uri", kind: "scalar", T: 9 /* ScalarType.STRING */ }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): GetBlocklistSubscriptionResponse { diff --git a/packages/bsky/src/hydration/actor.ts b/packages/bsky/src/hydration/actor.ts new file mode 100644 index 00000000000..4b7acd16edb --- /dev/null +++ b/packages/bsky/src/hydration/actor.ts @@ -0,0 +1,49 @@ +import { DataPlaneClient } from '../data-plane/client' +import { Record as ProfileRecord } from '../lexicon/types/app/bsky/actor/profile' + +export type ProfileInfo = { + did: string + handle: string | null + record: ProfileRecord | null +} + +export type ProfileInfos = Record + +export type ProfileViewerState = { + muted?: boolean + mutedByList?: string + blockedBy?: boolean + blocking?: string + blockingByList?: string + following?: string + followedBy?: string +} + +export type ProfileViewerStates = Record + +export type ProfileAgg = { + followers: number + follows: number + posts: number +} + +export type ProfileAggs = Record + +export class ActorHydrator { + constructor(public dataplane: DataPlaneClient) {} + + async getProfiles(dids: string[]): Promise { + throw new Error('unimplemented') + } + + async getProfileViewerStates( + dids: string[], + viewer: string, + ): Promise { + throw new Error('unimplemented') + } + + async getProfileAggregates(dids: string[]): Promise { + throw new Error('unimplemented') + } +} diff --git a/packages/bsky/src/hydration/graph.ts b/packages/bsky/src/hydration/graph.ts new file mode 100644 index 00000000000..291db5e84b6 --- /dev/null +++ b/packages/bsky/src/hydration/graph.ts @@ -0,0 +1,68 @@ +import * as ui8 from 'uint8arrays' +import { Record as ListRecord } from '../lexicon/types/app/bsky/graph/list' +import { DataPlaneClient } from '../data-plane/client' +import { jsonToLex } from '@atproto/lexicon' + +export type ListInfo = ListRecord + +export type ListInfos = Record + +export type ListViewerState = { + viewerMuted?: string + viewerListBlockUri?: string + viewerInList?: string +} + +export type ListViewerStates = Record + +export class GraphHydrator { + constructor(public dataplane: DataPlaneClient) {} + + async getListRecords(uris: string[]): Promise { + const res = await this.dataplane.getLists({ uris }) + return uris.reduce((acc, uri, i) => { + const list = res.records[i] + const parsed = JSON.parse(ui8.toString(list, 'utf8')) + acc[uri] = parsed ? (jsonToLex(parsed) as ListRecord) : null + return acc + }, {} as ListInfos) + } + + async getListsViewerState( + uris: string[], + viewer: string, + ): Promise { + const mutesAndBlocks = await Promise.all( + uris.map((uri) => this.getMutesAndBlocks(uri, viewer)), + ) + const listMemberships = await this.dataplane.getListMembership({ + actorDid: viewer, + listUris: uris, + }) + return uris.reduce((acc, uri, i) => { + acc[uri] = { + viewerMuted: mutesAndBlocks[i].muted ? uri : undefined, + viewerListBlockUri: mutesAndBlocks[i].listBlockUri, + viewerInList: listMemberships.listitemUris[i], + } + return acc + }, {} as ListViewerStates) + } + + private async getMutesAndBlocks(uri: string, viewer: string) { + const [muted, listBlockUri] = await Promise.all([ + this.dataplane.getMutelistSubscription({ + actorDid: viewer, + listUri: uri, + }), + this.dataplane.getBlocklistSubscription({ + actorDid: viewer, + listUri: uri, + }), + ]) + return { + muted: muted.subscribed, + listBlockUri: listBlockUri.listblockUri, + } + } +} diff --git a/packages/bsky/src/hydration/hydrator.ts b/packages/bsky/src/hydration/hydrator.ts new file mode 100644 index 00000000000..45de099b271 --- /dev/null +++ b/packages/bsky/src/hydration/hydrator.ts @@ -0,0 +1,77 @@ +import { DataPlaneClient } from '../data-plane/client' +import { + ActorHydrator, + ProfileAggs, + ProfileInfos, + ProfileViewerStates, +} from './actor' +import { GraphHydrator, ListInfos, ListViewerStates } from './graph' + +export type HydrationState = { + profiles?: ProfileInfos + profileViewers?: ProfileViewerStates + profileAggs?: ProfileAggs + lists?: ListInfos + listViewers?: ListViewerStates +} + +export class Hydrator { + actor: ActorHydrator + graph: GraphHydrator + + constructor(public dataplane: DataPlaneClient) { + this.actor = new ActorHydrator(dataplane) + this.graph = new GraphHydrator(dataplane) + } + + // - profile + // - list + async hydrateProfiles( + dids: string[], + viewer: string | null, + ): Promise { + const state: HydrationState = {} + const [profiles, profileViewers] = await Promise.all([ + this.actor.getProfiles(dids), + viewer ? this.actor.getProfileViewerStates(dids, viewer) : null, + ]) + state.profiles = profiles + if (profileViewers) { + state.profileViewers = profileViewers + const listUris = Object.values(profileViewers).reduce((acc, cur) => { + if (cur?.mutedByList) { + acc.push(cur.mutedByList) + } + if (cur?.blockingByList) { + acc.push(cur.blockingByList) + } + return acc + }, [] as string[]) + const [lists, listViewers] = await Promise.all([ + this.graph.getListRecords(listUris), + viewer ? this.graph.getListsViewerState(listUris, viewer) : null, + ]) + state.lists = lists + if (listViewers) { + state.listViewers = listViewers + } + } + return state + } + + // - profile + // - list + async hydrateProfilesDetailed( + dids: string[], + viewer: string | null, + ): Promise { + const [state, profileAggs] = await Promise.all([ + this.hydrateProfiles(dids, viewer), + this.actor.getProfileAggregates(dids), + ]) + return { + ...state, + profileAggs, + } + } +} diff --git a/packages/bsky/src/views/lists.ts b/packages/bsky/src/views/lists.ts new file mode 100644 index 00000000000..45f2914dc09 --- /dev/null +++ b/packages/bsky/src/views/lists.ts @@ -0,0 +1,44 @@ +import { ImageUriBuilder } from '../image/uri' +import { ListInfo } from '../services/graph/types' +import { ActorInfoMap } from '../services/actor' +import { ListView, ListViewBasic } from '../lexicon/types/app/bsky/graph/defs' + +export class GraphService { + constructor(public imgUriBuilder: ImageUriBuilder) {} + + formatListView(list: ListInfo, profiles: ActorInfoMap): ListView | undefined { + if (!profiles[list.creator]) { + return undefined + } + return { + ...this.formatListViewBasic(list), + creator: profiles[list.creator], + description: list.description ?? undefined, + descriptionFacets: list.descriptionFacets + ? JSON.parse(list.descriptionFacets) + : undefined, + indexedAt: list.sortAt, + } + } + + formatListViewBasic(list: ListInfo): ListViewBasic { + return { + uri: list.uri, + cid: list.cid, + name: list.name, + purpose: list.purpose, + avatar: list.avatarCid + ? this.imgUriBuilder.getPresetUri( + 'avatar', + list.creator, + list.avatarCid, + ) + : undefined, + indexedAt: list.sortAt, + viewer: { + muted: !!list.viewerMuted, + blocked: list.viewerListBlockUri ?? undefined, + }, + } + } +} From 9fcfdc0a67175975ca05d56110631eb946bc50a9 Mon Sep 17 00:00:00 2001 From: dholms Date: Wed, 6 Dec 2023 16:18:36 -0600 Subject: [PATCH 02/83] wip --- packages/bsky/src/hydration/actor.ts | 6 +++--- packages/bsky/src/hydration/graph.ts | 17 ++++++++--------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/bsky/src/hydration/actor.ts b/packages/bsky/src/hydration/actor.ts index 4b7acd16edb..3608b96bdee 100644 --- a/packages/bsky/src/hydration/actor.ts +++ b/packages/bsky/src/hydration/actor.ts @@ -7,7 +7,7 @@ export type ProfileInfo = { record: ProfileRecord | null } -export type ProfileInfos = Record +export type ProfileInfos = Map export type ProfileViewerState = { muted?: boolean @@ -19,7 +19,7 @@ export type ProfileViewerState = { followedBy?: string } -export type ProfileViewerStates = Record +export type ProfileViewerStates = Map export type ProfileAgg = { followers: number @@ -27,7 +27,7 @@ export type ProfileAgg = { posts: number } -export type ProfileAggs = Record +export type ProfileAggs = Map export class ActorHydrator { constructor(public dataplane: DataPlaneClient) {} diff --git a/packages/bsky/src/hydration/graph.ts b/packages/bsky/src/hydration/graph.ts index 291db5e84b6..2c61156a480 100644 --- a/packages/bsky/src/hydration/graph.ts +++ b/packages/bsky/src/hydration/graph.ts @@ -5,7 +5,7 @@ import { jsonToLex } from '@atproto/lexicon' export type ListInfo = ListRecord -export type ListInfos = Record +export type ListInfos = Map export type ListViewerState = { viewerMuted?: string @@ -13,7 +13,7 @@ export type ListViewerState = { viewerInList?: string } -export type ListViewerStates = Record +export type ListViewerStates = Map export class GraphHydrator { constructor(public dataplane: DataPlaneClient) {} @@ -23,9 +23,9 @@ export class GraphHydrator { return uris.reduce((acc, uri, i) => { const list = res.records[i] const parsed = JSON.parse(ui8.toString(list, 'utf8')) - acc[uri] = parsed ? (jsonToLex(parsed) as ListRecord) : null - return acc - }, {} as ListInfos) + const record = parsed ? (jsonToLex(parsed) as ListRecord) : null + return acc.set(uri, record) + }, new Map() as ListInfos) } async getListsViewerState( @@ -40,13 +40,12 @@ export class GraphHydrator { listUris: uris, }) return uris.reduce((acc, uri, i) => { - acc[uri] = { + return acc.set(uri, { viewerMuted: mutesAndBlocks[i].muted ? uri : undefined, viewerListBlockUri: mutesAndBlocks[i].listBlockUri, viewerInList: listMemberships.listitemUris[i], - } - return acc - }, {} as ListViewerStates) + }) + }, new Map() as ListViewerStates) } private async getMutesAndBlocks(uri: string, viewer: string) { From 1d61b4bee78004cff01a77b5df1703e66e4b13da Mon Sep 17 00:00:00 2001 From: dholms Date: Wed, 6 Dec 2023 16:47:07 -0600 Subject: [PATCH 03/83] stub out thick client --- packages/bsky/src/hydration/actor.ts | 11 ++--- packages/bsky/src/hydration/feed.ts | 61 ++++++++++++++++++++++++++++ packages/bsky/src/hydration/graph.ts | 31 +++++++++++--- packages/bsky/src/hydration/label.ts | 15 +++++++ packages/bsky/src/hydration/util.ts | 5 +++ 5 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 packages/bsky/src/hydration/feed.ts create mode 100644 packages/bsky/src/hydration/label.ts create mode 100644 packages/bsky/src/hydration/util.ts diff --git a/packages/bsky/src/hydration/actor.ts b/packages/bsky/src/hydration/actor.ts index 3608b96bdee..0c501f87f66 100644 --- a/packages/bsky/src/hydration/actor.ts +++ b/packages/bsky/src/hydration/actor.ts @@ -1,13 +1,14 @@ import { DataPlaneClient } from '../data-plane/client' import { Record as ProfileRecord } from '../lexicon/types/app/bsky/actor/profile' +import { HydrationMap } from './util' -export type ProfileInfo = { +export type Profile = { did: string handle: string | null record: ProfileRecord | null } -export type ProfileInfos = Map +export type Profiles = HydrationMap export type ProfileViewerState = { muted?: boolean @@ -19,7 +20,7 @@ export type ProfileViewerState = { followedBy?: string } -export type ProfileViewerStates = Map +export type ProfileViewerStates = HydrationMap export type ProfileAgg = { followers: number @@ -27,12 +28,12 @@ export type ProfileAgg = { posts: number } -export type ProfileAggs = Map +export type ProfileAggs = HydrationMap export class ActorHydrator { constructor(public dataplane: DataPlaneClient) {} - async getProfiles(dids: string[]): Promise { + async getProfiles(dids: string[]): Promise { throw new Error('unimplemented') } diff --git a/packages/bsky/src/hydration/feed.ts b/packages/bsky/src/hydration/feed.ts new file mode 100644 index 00000000000..9675f02548f --- /dev/null +++ b/packages/bsky/src/hydration/feed.ts @@ -0,0 +1,61 @@ +import { DataPlaneClient } from '../data-plane/client' +import { Record as PostRecord } from '../lexicon/types/app/bsky/feed/post' +import { Record as FeedGenRecord } from '../lexicon/types/app/bsky/feed/generator' +import { Record as ThreadgateRecord } from '../lexicon/types/app/bsky/feed/threadgate' +import { HydrationMap } from './util' + +export type Post = PostRecord +export type Posts = HydrationMap + +export type PostViewerState = { + muted?: boolean + mutedByList?: string + blockedBy?: boolean + blocking?: string + blockingByList?: string + following?: string + followedBy?: string +} + +export type PostViewerStates = Map + +export type PostAgg = { + followers: number + follows: number + posts: number +} + +export type PostAggs = Map + +export type FeedGen = FeedGenRecord +export type FeedGens = HydrationMap + +export type Threadgate = ThreadgateRecord +export type Threadgates = HydrationMap + +export class FeedHydrator { + constructor(public dataplane: DataPlaneClient) {} + + async getPosts(uris: string[]): Promise { + throw new Error('unimplemented') + } + + async getPostViewerStates( + uris: string[], + viewer: string, + ): Promise { + throw new Error('unimplemented') + } + + async getPostAggregates(uris: string[]): Promise { + throw new Error('unimplemented') + } + + async getFeedGens(uris: string[]): Promise { + throw new Error('unimplemented') + } + + async getThreadgatesForPosts(postUris: string[]): Promise { + throw new Error('unimplemented') + } +} diff --git a/packages/bsky/src/hydration/graph.ts b/packages/bsky/src/hydration/graph.ts index 2c61156a480..40eb4b1cd1d 100644 --- a/packages/bsky/src/hydration/graph.ts +++ b/packages/bsky/src/hydration/graph.ts @@ -2,10 +2,10 @@ import * as ui8 from 'uint8arrays' import { Record as ListRecord } from '../lexicon/types/app/bsky/graph/list' import { DataPlaneClient } from '../data-plane/client' import { jsonToLex } from '@atproto/lexicon' +import { HydrationMap } from './util' -export type ListInfo = ListRecord - -export type ListInfos = Map +export type List = ListRecord +export type Lists = HydrationMap export type ListViewerState = { viewerMuted?: string @@ -13,19 +13,34 @@ export type ListViewerState = { viewerInList?: string } -export type ListViewerStates = Map +export type ListViewerStates = HydrationMap + +export type RelationshipPair = [didA: string, didB: string] +export class Blocks { + has(didA: string, didB: string): boolean { + throw new Error('unimplemented') + } + + isBlocked(didA: string, didB: string): boolean { + throw new Error('unimplemented') + } + + merge(blocks: Blocks): Blocks { + throw new Error('unimplemented') + } +} export class GraphHydrator { constructor(public dataplane: DataPlaneClient) {} - async getListRecords(uris: string[]): Promise { + async getListRecords(uris: string[]): Promise { const res = await this.dataplane.getLists({ uris }) return uris.reduce((acc, uri, i) => { const list = res.records[i] const parsed = JSON.parse(ui8.toString(list, 'utf8')) const record = parsed ? (jsonToLex(parsed) as ListRecord) : null return acc.set(uri, record) - }, new Map() as ListInfos) + }, new Map() as Lists) } async getListsViewerState( @@ -48,6 +63,10 @@ export class GraphHydrator { }, new Map() as ListViewerStates) } + async getBidirectionalBlocks(pairs: RelationshipPair[]): Promise { + throw new Error('unimplemented') + } + private async getMutesAndBlocks(uri: string, viewer: string) { const [muted, listBlockUri] = await Promise.all([ this.dataplane.getMutelistSubscription({ diff --git a/packages/bsky/src/hydration/label.ts b/packages/bsky/src/hydration/label.ts new file mode 100644 index 00000000000..84337bcf54e --- /dev/null +++ b/packages/bsky/src/hydration/label.ts @@ -0,0 +1,15 @@ +import { DataPlaneClient } from '../data-plane/client' +import { Label } from '../lexicon/types/com/atproto/label/defs' +import { HydrationMap } from './util' + +export type { Label } from '../lexicon/types/com/atproto/label/defs' + +export type Labels = HydrationMap