@atproto/bsky 0.0.38 → 0.0.40
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 +14 -0
- package/dist/hydration/hydrator.d.ts +12 -2
- package/dist/hydration/label.d.ts +7 -3
- package/dist/hydration/util.d.ts +5 -2
- package/dist/index.js +216 -104
- package/dist/index.js.map +2 -2
- package/dist/lexicon/lexicons.d.ts +13 -0
- package/dist/lexicon/types/com/atproto/server/describeServer.d.ts +7 -0
- package/package.json +5 -5
- package/src/api/app/bsky/actor/getProfile.ts +10 -6
- package/src/api/app/bsky/actor/getProfiles.ts +2 -2
- package/src/api/app/bsky/actor/getSuggestions.ts +2 -2
- package/src/api/app/bsky/actor/searchActors.ts +7 -3
- package/src/api/app/bsky/actor/searchActorsTypeahead.ts +2 -2
- package/src/api/app/bsky/feed/getActorFeeds.ts +2 -2
- package/src/api/app/bsky/feed/getActorLikes.ts +2 -2
- package/src/api/app/bsky/feed/getAuthorFeed.ts +6 -2
- package/src/api/app/bsky/feed/getFeed.ts +2 -2
- package/src/api/app/bsky/feed/getFeedGenerator.ts +3 -6
- package/src/api/app/bsky/feed/getFeedGenerators.ts +2 -2
- package/src/api/app/bsky/feed/getLikes.ts +2 -2
- package/src/api/app/bsky/feed/getListFeed.ts +2 -2
- package/src/api/app/bsky/feed/getPostThread.ts +2 -2
- package/src/api/app/bsky/feed/getPosts.ts +2 -2
- package/src/api/app/bsky/feed/getRepostedBy.ts +2 -2
- package/src/api/app/bsky/feed/getSuggestedFeeds.ts +3 -5
- package/src/api/app/bsky/feed/getTimeline.ts +6 -3
- package/src/api/app/bsky/feed/searchPosts.ts +2 -2
- package/src/api/app/bsky/graph/getBlocks.ts +6 -3
- package/src/api/app/bsky/graph/getFollowers.ts +6 -2
- package/src/api/app/bsky/graph/getFollows.ts +6 -2
- package/src/api/app/bsky/graph/getList.ts +2 -2
- package/src/api/app/bsky/graph/getListBlocks.ts +6 -3
- package/src/api/app/bsky/graph/getListMutes.ts +6 -3
- package/src/api/app/bsky/graph/getLists.ts +2 -2
- package/src/api/app/bsky/graph/getMutes.ts +6 -3
- package/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts +3 -3
- package/src/api/app/bsky/labeler/getServices.ts +3 -3
- package/src/api/app/bsky/notification/listNotifications.ts +6 -3
- package/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +2 -2
- package/src/data-plane/server/routes/labels.ts +26 -8
- package/src/hydration/hydrator.ts +55 -10
- package/src/hydration/label.ts +33 -7
- package/src/hydration/util.ts +6 -2
- package/src/index.ts +1 -1
- package/src/lexicon/lexicons.ts +13 -0
- package/src/lexicon/types/com/atproto/server/describeServer.ts +18 -0
- package/src/views/index.ts +8 -8
- package/tests/__snapshots__/feed-generation.test.ts.snap +0 -45
- package/tests/data-plane/__snapshots__/indexing.test.ts.snap +0 -8
- package/tests/label-hydration.test.ts +31 -0
- package/tests/views/__snapshots__/author-feed.test.ts.snap +0 -46
- package/tests/views/__snapshots__/block-lists.test.ts.snap +0 -17
- package/tests/views/__snapshots__/blocks.test.ts.snap +0 -9
- package/tests/views/__snapshots__/labeler-service.test.ts.snap +0 -4
- package/tests/views/__snapshots__/list-feed.test.ts.snap +0 -20
- package/tests/views/__snapshots__/mute-lists.test.ts.snap +0 -18
- package/tests/views/__snapshots__/mutes.test.ts.snap +0 -4
- package/tests/views/__snapshots__/notifications.test.ts.snap +0 -9
- package/tests/views/__snapshots__/posts.test.ts.snap +0 -7
- package/tests/views/__snapshots__/profile.test.ts.snap +0 -6
- package/tests/views/__snapshots__/thread.test.ts.snap +0 -38
- package/tests/views/__snapshots__/timeline.test.ts.snap +0 -145
- package/tests/views/labeler-service.test.ts +2 -7
- package/tests/views/takedown-labels.test.ts +52 -0
|
@@ -10,11 +10,11 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
10
10
|
const { dids, detailed } = params
|
|
11
11
|
const viewer = auth.credentials.iss
|
|
12
12
|
const labelers = ctx.reqLabelers(req)
|
|
13
|
-
|
|
14
|
-
const hydration = await ctx.hydrator.hydrateLabelers(dids, {
|
|
13
|
+
const hydrateCtx = await ctx.hydrator.createContext({
|
|
15
14
|
viewer,
|
|
16
15
|
labelers,
|
|
17
16
|
})
|
|
17
|
+
const hydration = await ctx.hydrator.hydrateLabelers(dids, hydrateCtx)
|
|
18
18
|
|
|
19
19
|
const views = mapDefined(dids, (did) => {
|
|
20
20
|
if (detailed) {
|
|
@@ -39,7 +39,7 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
39
39
|
body: {
|
|
40
40
|
views,
|
|
41
41
|
},
|
|
42
|
-
headers: resHeaders({ labelers }),
|
|
42
|
+
headers: resHeaders({ labelers: hydrateCtx.labelers }),
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
45
|
})
|
|
@@ -28,12 +28,15 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
28
28
|
handler: async ({ params, auth, req }) => {
|
|
29
29
|
const viewer = auth.credentials.iss
|
|
30
30
|
const labelers = ctx.reqLabelers(req)
|
|
31
|
-
const hydrateCtx = { labelers, viewer }
|
|
32
|
-
const result = await listNotifications(
|
|
31
|
+
const hydrateCtx = await ctx.hydrator.createContext({ labelers, viewer })
|
|
32
|
+
const result = await listNotifications(
|
|
33
|
+
{ ...params, hydrateCtx: hydrateCtx.copy({ viewer }) },
|
|
34
|
+
ctx,
|
|
35
|
+
)
|
|
33
36
|
return {
|
|
34
37
|
encoding: 'application/json',
|
|
35
38
|
body: result,
|
|
36
|
-
headers: resHeaders({ labelers }),
|
|
39
|
+
headers: resHeaders({ labelers: hydrateCtx.labelers }),
|
|
37
40
|
}
|
|
38
41
|
},
|
|
39
42
|
})
|
|
@@ -13,7 +13,7 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
13
13
|
handler: async ({ auth, params, req }) => {
|
|
14
14
|
const viewer = auth.credentials.iss
|
|
15
15
|
const labelers = ctx.reqLabelers(req)
|
|
16
|
-
const hydrateCtx = { viewer, labelers }
|
|
16
|
+
const hydrateCtx = await ctx.hydrator.createContext({ viewer, labelers })
|
|
17
17
|
|
|
18
18
|
if (clearlyBadCursor(params.cursor)) {
|
|
19
19
|
return {
|
|
@@ -53,7 +53,7 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
53
53
|
feeds: feedViews,
|
|
54
54
|
cursor,
|
|
55
55
|
},
|
|
56
|
-
headers: resHeaders({ labelers }),
|
|
56
|
+
headers: resHeaders({ labelers: hydrateCtx.labelers }),
|
|
57
57
|
}
|
|
58
58
|
},
|
|
59
59
|
})
|
|
@@ -1,28 +1,46 @@
|
|
|
1
1
|
import * as ui8 from 'uint8arrays'
|
|
2
|
+
import { noUndefinedVals } from '@atproto/common'
|
|
2
3
|
import { ServiceImpl } from '@connectrpc/connect'
|
|
3
4
|
import { Service } from '../../../proto/bsky_connect'
|
|
4
5
|
import { Database } from '../db'
|
|
6
|
+
import { Selectable } from 'kysely'
|
|
7
|
+
import { Label } from '../db/tables/label'
|
|
8
|
+
|
|
9
|
+
type LabelRow = Selectable<Label>
|
|
5
10
|
|
|
6
11
|
export default (db: Database): Partial<ServiceImpl<typeof Service>> => ({
|
|
7
12
|
async getLabels(req) {
|
|
8
13
|
const { subjects, issuers } = req
|
|
9
14
|
if (subjects.length === 0 || issuers.length === 0) {
|
|
10
|
-
return {
|
|
15
|
+
return { labels: [] }
|
|
11
16
|
}
|
|
12
|
-
const res = await db.db
|
|
17
|
+
const res: LabelRow[] = await db.db
|
|
13
18
|
.selectFrom('label')
|
|
14
19
|
.where('uri', 'in', subjects)
|
|
15
20
|
.where('src', 'in', issuers)
|
|
16
21
|
.selectAll()
|
|
17
22
|
.execute()
|
|
18
23
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
const labelsBySubject = new Map<string, LabelRow[]>()
|
|
25
|
+
res.forEach((l) => {
|
|
26
|
+
const labels = labelsBySubject.get(l.uri) ?? []
|
|
27
|
+
labels.push(l)
|
|
28
|
+
labelsBySubject.set(l.uri, labels)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
// intentionally duplicate label results, appview frontend should be defensive to this
|
|
32
|
+
const labels = subjects.flatMap((sub) => {
|
|
33
|
+
const labelsForSub = labelsBySubject.get(sub) ?? []
|
|
34
|
+
return labelsForSub.map((l) => {
|
|
35
|
+
const formatted = noUndefinedVals({
|
|
36
|
+
...l,
|
|
37
|
+
cid: l.cid === '' ? undefined : l.cid,
|
|
38
|
+
neg: l.neg === true ? true : undefined,
|
|
39
|
+
})
|
|
40
|
+
return ui8.fromString(JSON.stringify(formatted), 'utf8')
|
|
41
|
+
})
|
|
25
42
|
})
|
|
43
|
+
|
|
26
44
|
return { labels }
|
|
27
45
|
},
|
|
28
46
|
})
|
|
@@ -29,7 +29,13 @@ import {
|
|
|
29
29
|
Labelers,
|
|
30
30
|
Labels,
|
|
31
31
|
} from './label'
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
HydrationMap,
|
|
34
|
+
Merges,
|
|
35
|
+
RecordInfo,
|
|
36
|
+
didFromUri,
|
|
37
|
+
urisByCollection,
|
|
38
|
+
} from './util'
|
|
33
39
|
import {
|
|
34
40
|
FeedGenAggs,
|
|
35
41
|
FeedGens,
|
|
@@ -47,7 +53,17 @@ import {
|
|
|
47
53
|
} from './feed'
|
|
48
54
|
import { ParsedLabelers } from '../util'
|
|
49
55
|
|
|
50
|
-
export
|
|
56
|
+
export class HydrateCtx {
|
|
57
|
+
labelers = this.vals.labelers
|
|
58
|
+
viewer = this.vals.viewer
|
|
59
|
+
includeTakedowns = this.vals.includeTakedowns
|
|
60
|
+
constructor(private vals: HydrateCtxVals) {}
|
|
61
|
+
copy<V extends Partial<HydrateCtxVals>>(vals?: V): HydrateCtx & V {
|
|
62
|
+
return new HydrateCtx({ ...this.vals, ...vals }) as HydrateCtx & V
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export type HydrateCtxVals = {
|
|
51
67
|
labelers: ParsedLabelers
|
|
52
68
|
viewer: string | null
|
|
53
69
|
includeTakedowns?: boolean
|
|
@@ -91,12 +107,17 @@ export class Hydrator {
|
|
|
91
107
|
feed: FeedHydrator
|
|
92
108
|
graph: GraphHydrator
|
|
93
109
|
label: LabelHydrator
|
|
110
|
+
serviceLabelers: Set<string>
|
|
94
111
|
|
|
95
|
-
constructor(
|
|
112
|
+
constructor(
|
|
113
|
+
public dataplane: DataPlaneClient,
|
|
114
|
+
serviceLabelers: string[] = [],
|
|
115
|
+
) {
|
|
96
116
|
this.actor = new ActorHydrator(dataplane)
|
|
97
117
|
this.feed = new FeedHydrator(dataplane)
|
|
98
118
|
this.graph = new GraphHydrator(dataplane)
|
|
99
119
|
this.label = new LabelHydrator(dataplane)
|
|
120
|
+
this.serviceLabelers = new Set(serviceLabelers)
|
|
100
121
|
}
|
|
101
122
|
|
|
102
123
|
// app.bsky.actor.defs#profileView
|
|
@@ -549,13 +570,14 @@ export class Hydrator {
|
|
|
549
570
|
): Promise<HydrationState> {
|
|
550
571
|
const [labelers, labelerAggs, labelerViewers, profileState] =
|
|
551
572
|
await Promise.all([
|
|
552
|
-
this.label.getLabelers(dids),
|
|
573
|
+
this.label.getLabelers(dids, ctx.includeTakedowns),
|
|
553
574
|
this.label.getLabelerAggregates(dids),
|
|
554
575
|
ctx.viewer
|
|
555
576
|
? this.label.getLabelerViewerStates(dids, ctx.viewer)
|
|
556
577
|
: undefined,
|
|
557
|
-
this.hydrateProfiles(dids
|
|
578
|
+
this.hydrateProfiles(dids, ctx),
|
|
558
579
|
])
|
|
580
|
+
actionTakedownLabels(dids, labelers, profileState.labels ?? new Labels())
|
|
559
581
|
return mergeStates(profileState, {
|
|
560
582
|
labelers,
|
|
561
583
|
labelerAggs,
|
|
@@ -613,8 +635,10 @@ export class Hydrator {
|
|
|
613
635
|
undefined
|
|
614
636
|
)
|
|
615
637
|
} else if (collection === ids.AppBskyLabelerService) {
|
|
638
|
+
if (parsed.rkey !== 'self') return
|
|
639
|
+
const did = parsed.hostname
|
|
616
640
|
return (
|
|
617
|
-
(await this.label.getLabelers([
|
|
641
|
+
(await this.label.getLabelers([did], includeTakedowns)).get(did) ??
|
|
618
642
|
undefined
|
|
619
643
|
)
|
|
620
644
|
} else if (collection === ids.AppBskyActorProfile) {
|
|
@@ -631,6 +655,30 @@ export class Hydrator {
|
|
|
631
655
|
}
|
|
632
656
|
}
|
|
633
657
|
}
|
|
658
|
+
|
|
659
|
+
async createContext(vals: HydrateCtxVals) {
|
|
660
|
+
// ensures we're only apply labelers that exist and are not taken down
|
|
661
|
+
const labelers = vals.labelers.dids
|
|
662
|
+
const nonServiceLabelers = labelers.filter(
|
|
663
|
+
(did) => !this.serviceLabelers.has(did),
|
|
664
|
+
)
|
|
665
|
+
const labelerActors = await this.actor.getActors(
|
|
666
|
+
nonServiceLabelers,
|
|
667
|
+
vals.includeTakedowns,
|
|
668
|
+
)
|
|
669
|
+
const availableDids = labelers.filter(
|
|
670
|
+
(did) => this.serviceLabelers.has(did) || !!labelerActors.get(did),
|
|
671
|
+
)
|
|
672
|
+
const availableLabelers = {
|
|
673
|
+
dids: availableDids,
|
|
674
|
+
redact: vals.labelers.redact,
|
|
675
|
+
}
|
|
676
|
+
return new HydrateCtx({
|
|
677
|
+
labelers: availableLabelers,
|
|
678
|
+
viewer: vals.viewer,
|
|
679
|
+
includeTakedowns: vals.includeTakedowns,
|
|
680
|
+
})
|
|
681
|
+
}
|
|
634
682
|
}
|
|
635
683
|
|
|
636
684
|
const listUrisFromProfileViewer = (item: ProfileViewerState | null) => {
|
|
@@ -770,10 +818,7 @@ export const mergeStates = (
|
|
|
770
818
|
}
|
|
771
819
|
}
|
|
772
820
|
|
|
773
|
-
const mergeMaps = <
|
|
774
|
-
mapA?: HydrationMap<T>,
|
|
775
|
-
mapB?: HydrationMap<T>,
|
|
776
|
-
): HydrationMap<T> | undefined => {
|
|
821
|
+
const mergeMaps = <M extends Merges>(mapA?: M, mapB?: M): M | undefined => {
|
|
777
822
|
if (!mapA) return mapB
|
|
778
823
|
if (!mapB) return mapA
|
|
779
824
|
return mapA.merge(mapB)
|
package/src/hydration/label.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { Label } from '../lexicon/types/com/atproto/label/defs'
|
|
|
3
3
|
import { Record as LabelerRecord } from '../lexicon/types/app/bsky/labeler/service'
|
|
4
4
|
import {
|
|
5
5
|
HydrationMap,
|
|
6
|
+
Merges,
|
|
6
7
|
RecordInfo,
|
|
7
8
|
parseJsonBytes,
|
|
8
9
|
parseRecord,
|
|
@@ -16,10 +17,36 @@ export type { Label } from '../lexicon/types/com/atproto/label/defs'
|
|
|
16
17
|
|
|
17
18
|
export type SubjectLabels = {
|
|
18
19
|
isTakendown: boolean
|
|
19
|
-
labels: Label
|
|
20
|
+
labels: HydrationMap<Label> // src + val -> label
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
export
|
|
23
|
+
export class Labels extends HydrationMap<SubjectLabels> implements Merges {
|
|
24
|
+
static key(label: Label) {
|
|
25
|
+
return `${label.src}::${label.val}`
|
|
26
|
+
}
|
|
27
|
+
merge(map: Labels): this {
|
|
28
|
+
map.forEach((theirs, key) => {
|
|
29
|
+
if (!theirs) return
|
|
30
|
+
const mine = this.get(key)
|
|
31
|
+
if (mine) {
|
|
32
|
+
mine.isTakendown = mine.isTakendown || theirs.isTakendown
|
|
33
|
+
mine.labels = mine.labels.merge(theirs.labels)
|
|
34
|
+
} else {
|
|
35
|
+
this.set(key, theirs)
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
return this
|
|
39
|
+
}
|
|
40
|
+
getBySubject(sub: string): Label[] {
|
|
41
|
+
const it = this.get(sub)?.labels.values()
|
|
42
|
+
if (!it) return []
|
|
43
|
+
const labels: Label[] = []
|
|
44
|
+
for (const label of it) {
|
|
45
|
+
if (label) labels.push(label)
|
|
46
|
+
}
|
|
47
|
+
return labels
|
|
48
|
+
}
|
|
49
|
+
}
|
|
23
50
|
|
|
24
51
|
export type LabelerAgg = {
|
|
25
52
|
likes: number
|
|
@@ -43,8 +70,7 @@ export class LabelHydrator {
|
|
|
43
70
|
subjects: string[],
|
|
44
71
|
labelers: ParsedLabelers,
|
|
45
72
|
): Promise<Labels> {
|
|
46
|
-
if (!subjects.length || !labelers.dids.length)
|
|
47
|
-
return new HydrationMap<SubjectLabels>()
|
|
73
|
+
if (!subjects.length || !labelers.dids.length) return new Labels()
|
|
48
74
|
const res = await this.dataplane.getLabels({
|
|
49
75
|
subjects,
|
|
50
76
|
issuers: labelers.dids,
|
|
@@ -57,11 +83,11 @@ export class LabelHydrator {
|
|
|
57
83
|
if (!entry) {
|
|
58
84
|
entry = {
|
|
59
85
|
isTakendown: false,
|
|
60
|
-
labels:
|
|
86
|
+
labels: new HydrationMap(),
|
|
61
87
|
}
|
|
62
88
|
acc.set(label.uri, entry)
|
|
63
89
|
}
|
|
64
|
-
entry.labels.
|
|
90
|
+
entry.labels.set(Labels.key(label), label)
|
|
65
91
|
if (
|
|
66
92
|
TAKEDOWN_LABELS.includes(label.val) &&
|
|
67
93
|
!label.neg &&
|
|
@@ -70,7 +96,7 @@ export class LabelHydrator {
|
|
|
70
96
|
entry.isTakendown = true
|
|
71
97
|
}
|
|
72
98
|
return acc
|
|
73
|
-
}, new
|
|
99
|
+
}, new Labels())
|
|
74
100
|
}
|
|
75
101
|
|
|
76
102
|
async getLabelers(
|
package/src/hydration/util.ts
CHANGED
|
@@ -5,8 +5,8 @@ import * as ui8 from 'uint8arrays'
|
|
|
5
5
|
import { lexicons } from '../lexicon/lexicons'
|
|
6
6
|
import { Record } from '../proto/bsky_pb'
|
|
7
7
|
|
|
8
|
-
export class HydrationMap<T> extends Map<string, T | null> {
|
|
9
|
-
merge(map: HydrationMap<T>):
|
|
8
|
+
export class HydrationMap<T> extends Map<string, T | null> implements Merges {
|
|
9
|
+
merge(map: HydrationMap<T>): this {
|
|
10
10
|
map.forEach((val, key) => {
|
|
11
11
|
this.set(key, val)
|
|
12
12
|
})
|
|
@@ -14,6 +14,10 @@ export class HydrationMap<T> extends Map<string, T | null> {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
export interface Merges {
|
|
18
|
+
merge<T extends this>(map: T): this
|
|
19
|
+
}
|
|
20
|
+
|
|
17
21
|
export type RecordInfo<T> = {
|
|
18
22
|
record: T
|
|
19
23
|
cid: string
|
package/src/index.ts
CHANGED
|
@@ -77,7 +77,7 @@ export class BskyAppView {
|
|
|
77
77
|
httpVersion: config.dataplaneHttpVersion,
|
|
78
78
|
rejectUnauthorized: !config.dataplaneIgnoreBadTls,
|
|
79
79
|
})
|
|
80
|
-
const hydrator = new Hydrator(dataplane)
|
|
80
|
+
const hydrator = new Hydrator(dataplane, config.labelsFromIssuerDids)
|
|
81
81
|
const views = new Views(imgUriBuilder)
|
|
82
82
|
|
|
83
83
|
const bsyncClient = createBsyncClient({
|
package/src/lexicon/lexicons.ts
CHANGED
|
@@ -2420,6 +2420,11 @@ export const schemaDict = {
|
|
|
2420
2420
|
description: 'URLs of service policy documents.',
|
|
2421
2421
|
ref: 'lex:com.atproto.server.describeServer#links',
|
|
2422
2422
|
},
|
|
2423
|
+
contact: {
|
|
2424
|
+
type: 'ref',
|
|
2425
|
+
description: 'Contact information',
|
|
2426
|
+
ref: 'lex:com.atproto.server.describeServer#contact',
|
|
2427
|
+
},
|
|
2423
2428
|
did: {
|
|
2424
2429
|
type: 'string',
|
|
2425
2430
|
format: 'did',
|
|
@@ -2439,6 +2444,14 @@ export const schemaDict = {
|
|
|
2439
2444
|
},
|
|
2440
2445
|
},
|
|
2441
2446
|
},
|
|
2447
|
+
contact: {
|
|
2448
|
+
type: 'object',
|
|
2449
|
+
properties: {
|
|
2450
|
+
email: {
|
|
2451
|
+
type: 'string',
|
|
2452
|
+
},
|
|
2453
|
+
},
|
|
2454
|
+
},
|
|
2442
2455
|
},
|
|
2443
2456
|
},
|
|
2444
2457
|
ComAtprotoServerGetAccountInviteCodes: {
|
|
@@ -20,6 +20,7 @@ export interface OutputSchema {
|
|
|
20
20
|
/** List of domain suffixes that can be used in account handles. */
|
|
21
21
|
availableUserDomains: string[]
|
|
22
22
|
links?: Links
|
|
23
|
+
contact?: Contact
|
|
23
24
|
did: string
|
|
24
25
|
[k: string]: unknown
|
|
25
26
|
}
|
|
@@ -66,3 +67,20 @@ export function isLinks(v: unknown): v is Links {
|
|
|
66
67
|
export function validateLinks(v: unknown): ValidationResult {
|
|
67
68
|
return lexicons.validate('com.atproto.server.describeServer#links', v)
|
|
68
69
|
}
|
|
70
|
+
|
|
71
|
+
export interface Contact {
|
|
72
|
+
email?: string
|
|
73
|
+
[k: string]: unknown
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function isContact(v: unknown): v is Contact {
|
|
77
|
+
return (
|
|
78
|
+
isObj(v) &&
|
|
79
|
+
hasProp(v, '$type') &&
|
|
80
|
+
v.$type === 'com.atproto.server.describeServer#contact'
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function validateContact(v: unknown): ValidationResult {
|
|
85
|
+
return lexicons.validate('com.atproto.server.describeServer#contact', v)
|
|
86
|
+
}
|
package/src/views/index.ts
CHANGED
|
@@ -136,8 +136,8 @@ export class Views {
|
|
|
136
136
|
'self',
|
|
137
137
|
).toString()
|
|
138
138
|
const labels = [
|
|
139
|
-
...(state.labels?.
|
|
140
|
-
...(state.labels?.
|
|
139
|
+
...(state.labels?.getBySubject(did) ?? []),
|
|
140
|
+
...(state.labels?.getBySubject(profileUri) ?? []),
|
|
141
141
|
...this.selfLabels({
|
|
142
142
|
uri: profileUri,
|
|
143
143
|
cid: actor.profileCid?.toString(),
|
|
@@ -225,7 +225,7 @@ export class Views {
|
|
|
225
225
|
return undefined
|
|
226
226
|
}
|
|
227
227
|
const listViewer = state.listViewers?.get(uri)
|
|
228
|
-
const labels = state.labels?.
|
|
228
|
+
const labels = state.labels?.getBySubject(uri) ?? []
|
|
229
229
|
const creator = new AtUri(uri).hostname
|
|
230
230
|
return {
|
|
231
231
|
uri,
|
|
@@ -267,7 +267,7 @@ export class Views {
|
|
|
267
267
|
? normalizeDatetimeAlways(record.createdAt)
|
|
268
268
|
: new Date(0).toISOString()
|
|
269
269
|
return record.labels.values.map(({ val }) => {
|
|
270
|
-
return { src, uri, cid, val, cts
|
|
270
|
+
return { src, uri, cid, val, cts }
|
|
271
271
|
})
|
|
272
272
|
}
|
|
273
273
|
|
|
@@ -281,7 +281,7 @@ export class Views {
|
|
|
281
281
|
|
|
282
282
|
const uri = AtUri.make(did, ids.AppBskyLabelerService, 'self').toString()
|
|
283
283
|
const labels = [
|
|
284
|
-
...(state.labels?.
|
|
284
|
+
...(state.labels?.getBySubject(uri) ?? []),
|
|
285
285
|
...this.selfLabels({
|
|
286
286
|
uri,
|
|
287
287
|
cid: labeler.cid.toString(),
|
|
@@ -351,7 +351,7 @@ export class Views {
|
|
|
351
351
|
if (!creator) return
|
|
352
352
|
const viewer = state.feedgenViewers?.get(uri)
|
|
353
353
|
const aggs = state.feedgenAggs?.get(uri)
|
|
354
|
-
const labels = state.labels?.
|
|
354
|
+
const labels = state.labels?.getBySubject(uri) ?? []
|
|
355
355
|
|
|
356
356
|
return {
|
|
357
357
|
uri,
|
|
@@ -408,7 +408,7 @@ export class Views {
|
|
|
408
408
|
parsedUri.rkey,
|
|
409
409
|
).toString()
|
|
410
410
|
const labels = [
|
|
411
|
-
...(state.labels?.
|
|
411
|
+
...(state.labels?.getBySubject(uri) ?? []),
|
|
412
412
|
...this.selfLabels({
|
|
413
413
|
uri,
|
|
414
414
|
cid: post.cid,
|
|
@@ -886,7 +886,7 @@ export class Views {
|
|
|
886
886
|
recordInfo = state.follows?.get(notif.uri)
|
|
887
887
|
}
|
|
888
888
|
if (!recordInfo) return
|
|
889
|
-
const labels = state.labels?.
|
|
889
|
+
const labels = state.labels?.getBySubject(notif.uri) ?? []
|
|
890
890
|
const selfLabels = this.selfLabels({
|
|
891
891
|
uri: notif.uri,
|
|
892
892
|
cid: recordInfo.cid,
|