@atproto/bsky 0.0.37 → 0.0.38

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.
Files changed (138) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/api/app/bsky/feed/getAuthorFeed.d.ts +2 -3
  3. package/dist/api/app/bsky/feed/getListFeed.d.ts +2 -2
  4. package/dist/api/app/bsky/feed/getTimeline.d.ts +4 -2
  5. package/dist/api/app/bsky/labeler/getServices.d.ts +3 -0
  6. package/dist/api/util.d.ts +9 -2
  7. package/dist/auth-verifier.d.ts +1 -1
  8. package/dist/context.d.ts +3 -0
  9. package/dist/data-plane/server/db/database-schema.d.ts +2 -2
  10. package/dist/data-plane/server/db/migrations/20240226T225725627Z-labelers.d.ts +3 -0
  11. package/dist/data-plane/server/db/migrations/index.d.ts +1 -0
  12. package/dist/data-plane/server/db/tables/labeler.d.ts +13 -0
  13. package/dist/data-plane/server/indexing/index.d.ts +2 -0
  14. package/dist/data-plane/server/indexing/plugins/labeler.d.ts +10 -0
  15. package/dist/data-plane/server/util.d.ts +6 -6
  16. package/dist/hydration/actor.d.ts +3 -0
  17. package/dist/hydration/hydrator.d.ts +27 -22
  18. package/dist/hydration/label.d.ts +23 -9
  19. package/dist/index.js +4068 -4641
  20. package/dist/index.js.map +3 -3
  21. package/dist/lexicon/index.d.ts +7 -27
  22. package/dist/lexicon/lexicons.d.ts +507 -1467
  23. package/dist/lexicon/types/app/bsky/actor/defs.d.ts +23 -1
  24. package/dist/lexicon/types/app/bsky/embed/record.d.ts +2 -1
  25. package/dist/lexicon/types/app/bsky/feed/defs.d.ts +1 -0
  26. package/dist/lexicon/types/app/bsky/graph/defs.d.ts +3 -0
  27. package/dist/lexicon/types/app/bsky/labeler/defs.d.ts +41 -0
  28. package/dist/lexicon/types/{com/atproto/admin/searchRepos.d.ts → app/bsky/labeler/getServices.d.ts} +7 -7
  29. package/dist/lexicon/types/app/bsky/labeler/service.d.ts +14 -0
  30. package/dist/lexicon/types/com/atproto/admin/defs.d.ts +0 -304
  31. package/dist/lexicon/types/com/atproto/label/defs.d.ts +23 -0
  32. package/dist/proto/bsky_connect.d.ts +7 -1
  33. package/dist/proto/bsky_pb.d.ts +25 -0
  34. package/dist/util.d.ts +7 -0
  35. package/dist/views/index.d.ts +3 -0
  36. package/dist/views/types.d.ts +2 -1
  37. package/package.json +14 -13
  38. package/proto/bsky.proto +12 -0
  39. package/src/api/app/bsky/actor/getProfile.ts +21 -17
  40. package/src/api/app/bsky/actor/getProfiles.ts +16 -7
  41. package/src/api/app/bsky/actor/getSuggestions.ts +18 -13
  42. package/src/api/app/bsky/actor/searchActors.ts +9 -5
  43. package/src/api/app/bsky/actor/searchActorsTypeahead.ts +12 -5
  44. package/src/api/app/bsky/feed/getActorFeeds.ts +16 -6
  45. package/src/api/app/bsky/feed/getActorLikes.ts +18 -8
  46. package/src/api/app/bsky/feed/getAuthorFeed.ts +18 -19
  47. package/src/api/app/bsky/feed/getFeed.ts +14 -7
  48. package/src/api/app/bsky/feed/getFeedGenerator.ts +8 -2
  49. package/src/api/app/bsky/feed/getFeedGenerators.ts +16 -5
  50. package/src/api/app/bsky/feed/getLikes.ts +13 -6
  51. package/src/api/app/bsky/feed/getListFeed.ts +13 -7
  52. package/src/api/app/bsky/feed/getPostThread.ts +15 -8
  53. package/src/api/app/bsky/feed/getPosts.ts +14 -5
  54. package/src/api/app/bsky/feed/getRepostedBy.ts +13 -6
  55. package/src/api/app/bsky/feed/getSuggestedFeeds.ts +8 -2
  56. package/src/api/app/bsky/feed/getTimeline.ts +14 -8
  57. package/src/api/app/bsky/feed/searchPosts.ts +9 -5
  58. package/src/api/app/bsky/graph/getBlocks.ts +10 -9
  59. package/src/api/app/bsky/graph/getFollowers.ts +23 -15
  60. package/src/api/app/bsky/graph/getFollows.ts +23 -15
  61. package/src/api/app/bsky/graph/getList.ts +14 -8
  62. package/src/api/app/bsky/graph/getListBlocks.ts +10 -7
  63. package/src/api/app/bsky/graph/getListMutes.ts +10 -7
  64. package/src/api/app/bsky/graph/getLists.ts +9 -7
  65. package/src/api/app/bsky/graph/getMutes.ts +10 -8
  66. package/src/api/app/bsky/graph/getSuggestedFollowsByActor.ts +10 -7
  67. package/src/api/app/bsky/graph/muteActor.ts +1 -1
  68. package/src/api/app/bsky/labeler/getServices.ts +46 -0
  69. package/src/api/app/bsky/notification/listNotifications.ts +12 -8
  70. package/src/api/app/bsky/unspecced/getPopularFeedGenerators.ts +6 -3
  71. package/src/api/com/atproto/admin/getAccountInfos.ts +10 -3
  72. package/src/api/index.ts +2 -0
  73. package/src/api/util.ts +19 -4
  74. package/src/auth-verifier.ts +2 -2
  75. package/src/context.ts +20 -0
  76. package/src/data-plane/server/db/database-schema.ts +4 -4
  77. package/src/data-plane/server/db/migrations/20240226T225725627Z-labelers.ts +27 -0
  78. package/src/data-plane/server/db/migrations/index.ts +1 -0
  79. package/src/data-plane/server/db/tables/labeler.ts +16 -0
  80. package/src/data-plane/server/indexing/index.ts +4 -0
  81. package/src/data-plane/server/indexing/plugins/labeler.ts +77 -0
  82. package/src/data-plane/server/routes/interactions.ts +17 -1
  83. package/src/data-plane/server/routes/profile.ts +15 -1
  84. package/src/data-plane/server/routes/records.ts +1 -0
  85. package/src/hydration/actor.ts +6 -0
  86. package/src/hydration/hydrator.ts +171 -97
  87. package/src/hydration/label.ts +106 -20
  88. package/src/index.ts +1 -3
  89. package/src/lexicon/index.ts +22 -137
  90. package/src/lexicon/lexicons.ts +502 -1598
  91. package/src/lexicon/types/app/bsky/actor/defs.ts +57 -1
  92. package/src/lexicon/types/app/bsky/embed/record.ts +2 -0
  93. package/src/lexicon/types/app/bsky/feed/defs.ts +1 -0
  94. package/src/lexicon/types/app/bsky/graph/defs.ts +3 -0
  95. package/src/lexicon/types/app/bsky/labeler/defs.ts +93 -0
  96. package/src/lexicon/types/{com/atproto/admin/searchRepos.ts → app/bsky/labeler/getServices.ts} +8 -8
  97. package/src/lexicon/types/app/bsky/labeler/service.ts +31 -0
  98. package/src/lexicon/types/com/atproto/admin/defs.ts +0 -694
  99. package/src/lexicon/types/com/atproto/label/defs.ts +78 -0
  100. package/src/proto/bsky_connect.ts +11 -0
  101. package/src/proto/bsky_pb.ts +146 -0
  102. package/src/util.ts +44 -0
  103. package/src/views/index.ts +76 -7
  104. package/src/views/types.ts +6 -3
  105. package/tests/__snapshots__/feed-generation.test.ts.snap +12 -0
  106. package/tests/_util.ts +21 -0
  107. package/tests/data-plane/__snapshots__/indexing.test.ts.snap +20 -0
  108. package/tests/label-hydration.test.ts +162 -0
  109. package/tests/views/__snapshots__/block-lists.test.ts.snap +7 -0
  110. package/tests/views/__snapshots__/labeler-service.test.ts.snap +160 -0
  111. package/tests/views/__snapshots__/mute-lists.test.ts.snap +10 -0
  112. package/tests/views/__snapshots__/profile.test.ts.snap +40 -0
  113. package/tests/views/__snapshots__/threadgating.test.ts.snap +2 -0
  114. package/tests/views/labeler-service.test.ts +156 -0
  115. package/tests/views/takedown-labels.test.ts +133 -0
  116. package/tests/views/timeline.test.ts +7 -2
  117. package/dist/data-plane/server/db/tables/moderation.d.ts +0 -42
  118. package/dist/lexicon/types/com/atproto/admin/createCommunicationTemplate.d.ts +0 -37
  119. package/dist/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.d.ts +0 -25
  120. package/dist/lexicon/types/com/atproto/admin/emitModerationEvent.d.ts +0 -45
  121. package/dist/lexicon/types/com/atproto/admin/getModerationEvent.d.ts +0 -29
  122. package/dist/lexicon/types/com/atproto/admin/getRecord.d.ts +0 -31
  123. package/dist/lexicon/types/com/atproto/admin/getRepo.d.ts +0 -30
  124. package/dist/lexicon/types/com/atproto/admin/listCommunicationTemplates.d.ts +0 -31
  125. package/dist/lexicon/types/com/atproto/admin/queryModerationEvents.d.ts +0 -48
  126. package/dist/lexicon/types/com/atproto/admin/queryModerationStatuses.d.ts +0 -50
  127. package/dist/lexicon/types/com/atproto/admin/updateCommunicationTemplate.d.ts +0 -39
  128. package/src/data-plane/server/db/tables/moderation.ts +0 -59
  129. package/src/lexicon/types/com/atproto/admin/createCommunicationTemplate.ts +0 -54
  130. package/src/lexicon/types/com/atproto/admin/deleteCommunicationTemplate.ts +0 -38
  131. package/src/lexicon/types/com/atproto/admin/emitModerationEvent.ts +0 -67
  132. package/src/lexicon/types/com/atproto/admin/getModerationEvent.ts +0 -41
  133. package/src/lexicon/types/com/atproto/admin/getRecord.ts +0 -43
  134. package/src/lexicon/types/com/atproto/admin/getRepo.ts +0 -42
  135. package/src/lexicon/types/com/atproto/admin/listCommunicationTemplates.ts +0 -44
  136. package/src/lexicon/types/com/atproto/admin/queryModerationEvents.ts +0 -73
  137. package/src/lexicon/types/com/atproto/admin/queryModerationStatuses.ts +0 -74
  138. package/src/lexicon/types/com/atproto/admin/updateCommunicationTemplate.ts +0 -57
@@ -8,6 +8,8 @@ import { CID } from 'multiformats/cid'
8
8
 
9
9
  /** Metadata tag on an atproto resource (eg, repo or record). */
10
10
  export interface Label {
11
+ /** The AT Protocol version of the label object. */
12
+ ver?: number
11
13
  /** DID of the actor who created this label. */
12
14
  src: string
13
15
  /** AT URI of the record, repository (account), or other resource that this label applies to. */
@@ -20,6 +22,10 @@ export interface Label {
20
22
  neg?: boolean
21
23
  /** Timestamp when this label was created. */
22
24
  cts: string
25
+ /** Timestamp at which this label expires (no longer applies). */
26
+ exp?: string
27
+ /** Signature of dag-cbor encoded label. */
28
+ sig?: Uint8Array
23
29
  [k: string]: unknown
24
30
  }
25
31
 
@@ -71,3 +77,75 @@ export function isSelfLabel(v: unknown): v is SelfLabel {
71
77
  export function validateSelfLabel(v: unknown): ValidationResult {
72
78
  return lexicons.validate('com.atproto.label.defs#selfLabel', v)
73
79
  }
80
+
81
+ /** Declares a label value and its expected interpertations and behaviors. */
82
+ export interface LabelValueDefinition {
83
+ /** The value of the label being defined. Must only include lowercase ascii and the '-' character ([a-z-]+). */
84
+ identifier: string
85
+ /** How should a client visually convey this label? 'inform' means neutral and informational; 'alert' means negative and warning; 'none' means show nothing. */
86
+ severity: 'inform' | 'alert' | 'none' | (string & {})
87
+ /** What should this label hide in the UI, if applied? 'content' hides all of the target; 'media' hides the images/video/audio; 'none' hides nothing. */
88
+ blurs: 'content' | 'media' | 'none' | (string & {})
89
+ /** The default setting for this label. */
90
+ defaultSetting: 'ignore' | 'warn' | 'hide' | (string & {})
91
+ /** Does the user need to have adult content enabled in order to configure this label? */
92
+ adultOnly?: boolean
93
+ locales: LabelValueDefinitionStrings[]
94
+ [k: string]: unknown
95
+ }
96
+
97
+ export function isLabelValueDefinition(v: unknown): v is LabelValueDefinition {
98
+ return (
99
+ isObj(v) &&
100
+ hasProp(v, '$type') &&
101
+ v.$type === 'com.atproto.label.defs#labelValueDefinition'
102
+ )
103
+ }
104
+
105
+ export function validateLabelValueDefinition(v: unknown): ValidationResult {
106
+ return lexicons.validate('com.atproto.label.defs#labelValueDefinition', v)
107
+ }
108
+
109
+ /** Strings which describe the label in the UI, localized into a specific language. */
110
+ export interface LabelValueDefinitionStrings {
111
+ /** The code of the language these strings are written in. */
112
+ lang: string
113
+ /** A short human-readable name for the label. */
114
+ name: string
115
+ /** A longer description of what the label means and why it might be applied. */
116
+ description: string
117
+ [k: string]: unknown
118
+ }
119
+
120
+ export function isLabelValueDefinitionStrings(
121
+ v: unknown,
122
+ ): v is LabelValueDefinitionStrings {
123
+ return (
124
+ isObj(v) &&
125
+ hasProp(v, '$type') &&
126
+ v.$type === 'com.atproto.label.defs#labelValueDefinitionStrings'
127
+ )
128
+ }
129
+
130
+ export function validateLabelValueDefinitionStrings(
131
+ v: unknown,
132
+ ): ValidationResult {
133
+ return lexicons.validate(
134
+ 'com.atproto.label.defs#labelValueDefinitionStrings',
135
+ v,
136
+ )
137
+ }
138
+
139
+ export type LabelValue =
140
+ | '!hide'
141
+ | '!no-promote'
142
+ | '!warn'
143
+ | '!no-unauthenticated'
144
+ | 'dmca-violation'
145
+ | 'doxxing'
146
+ | 'porn'
147
+ | 'sexual'
148
+ | 'nudity'
149
+ | 'nsfl'
150
+ | 'gore'
151
+ | (string & {})
@@ -74,6 +74,8 @@ import {
74
74
  GetIdentityByHandleResponse,
75
75
  GetInteractionCountsRequest,
76
76
  GetInteractionCountsResponse,
77
+ GetLabelerRecordsRequest,
78
+ GetLabelerRecordsResponse,
77
79
  GetLabelsRequest,
78
80
  GetLabelsResponse,
79
81
  GetLatestRevRequest,
@@ -272,6 +274,15 @@ export const Service = {
272
274
  O: GetThreadGateRecordsResponse,
273
275
  kind: MethodKind.Unary,
274
276
  },
277
+ /**
278
+ * @generated from rpc bsky.Service.GetLabelerRecords
279
+ */
280
+ getLabelerRecords: {
281
+ name: 'GetLabelerRecords',
282
+ I: GetLabelerRecordsRequest,
283
+ O: GetLabelerRecordsResponse,
284
+ kind: MethodKind.Unary,
285
+ },
275
286
  /**
276
287
  * Follows
277
288
  *
@@ -1474,6 +1474,122 @@ export class GetThreadGateRecordsResponse extends Message<GetThreadGateRecordsRe
1474
1474
  }
1475
1475
  }
1476
1476
 
1477
+ /**
1478
+ * @generated from message bsky.GetLabelerRecordsRequest
1479
+ */
1480
+ export class GetLabelerRecordsRequest extends Message<GetLabelerRecordsRequest> {
1481
+ /**
1482
+ * @generated from field: repeated string uris = 1;
1483
+ */
1484
+ uris: string[] = []
1485
+
1486
+ constructor(data?: PartialMessage<GetLabelerRecordsRequest>) {
1487
+ super()
1488
+ proto3.util.initPartial(data, this)
1489
+ }
1490
+
1491
+ static readonly runtime: typeof proto3 = proto3
1492
+ static readonly typeName = 'bsky.GetLabelerRecordsRequest'
1493
+ static readonly fields: FieldList = proto3.util.newFieldList(() => [
1494
+ {
1495
+ no: 1,
1496
+ name: 'uris',
1497
+ kind: 'scalar',
1498
+ T: 9 /* ScalarType.STRING */,
1499
+ repeated: true,
1500
+ },
1501
+ ])
1502
+
1503
+ static fromBinary(
1504
+ bytes: Uint8Array,
1505
+ options?: Partial<BinaryReadOptions>,
1506
+ ): GetLabelerRecordsRequest {
1507
+ return new GetLabelerRecordsRequest().fromBinary(bytes, options)
1508
+ }
1509
+
1510
+ static fromJson(
1511
+ jsonValue: JsonValue,
1512
+ options?: Partial<JsonReadOptions>,
1513
+ ): GetLabelerRecordsRequest {
1514
+ return new GetLabelerRecordsRequest().fromJson(jsonValue, options)
1515
+ }
1516
+
1517
+ static fromJsonString(
1518
+ jsonString: string,
1519
+ options?: Partial<JsonReadOptions>,
1520
+ ): GetLabelerRecordsRequest {
1521
+ return new GetLabelerRecordsRequest().fromJsonString(jsonString, options)
1522
+ }
1523
+
1524
+ static equals(
1525
+ a:
1526
+ | GetLabelerRecordsRequest
1527
+ | PlainMessage<GetLabelerRecordsRequest>
1528
+ | undefined,
1529
+ b:
1530
+ | GetLabelerRecordsRequest
1531
+ | PlainMessage<GetLabelerRecordsRequest>
1532
+ | undefined,
1533
+ ): boolean {
1534
+ return proto3.util.equals(GetLabelerRecordsRequest, a, b)
1535
+ }
1536
+ }
1537
+
1538
+ /**
1539
+ * @generated from message bsky.GetLabelerRecordsResponse
1540
+ */
1541
+ export class GetLabelerRecordsResponse extends Message<GetLabelerRecordsResponse> {
1542
+ /**
1543
+ * @generated from field: repeated bsky.Record records = 1;
1544
+ */
1545
+ records: Record[] = []
1546
+
1547
+ constructor(data?: PartialMessage<GetLabelerRecordsResponse>) {
1548
+ super()
1549
+ proto3.util.initPartial(data, this)
1550
+ }
1551
+
1552
+ static readonly runtime: typeof proto3 = proto3
1553
+ static readonly typeName = 'bsky.GetLabelerRecordsResponse'
1554
+ static readonly fields: FieldList = proto3.util.newFieldList(() => [
1555
+ { no: 1, name: 'records', kind: 'message', T: Record, repeated: true },
1556
+ ])
1557
+
1558
+ static fromBinary(
1559
+ bytes: Uint8Array,
1560
+ options?: Partial<BinaryReadOptions>,
1561
+ ): GetLabelerRecordsResponse {
1562
+ return new GetLabelerRecordsResponse().fromBinary(bytes, options)
1563
+ }
1564
+
1565
+ static fromJson(
1566
+ jsonValue: JsonValue,
1567
+ options?: Partial<JsonReadOptions>,
1568
+ ): GetLabelerRecordsResponse {
1569
+ return new GetLabelerRecordsResponse().fromJson(jsonValue, options)
1570
+ }
1571
+
1572
+ static fromJsonString(
1573
+ jsonString: string,
1574
+ options?: Partial<JsonReadOptions>,
1575
+ ): GetLabelerRecordsResponse {
1576
+ return new GetLabelerRecordsResponse().fromJsonString(jsonString, options)
1577
+ }
1578
+
1579
+ static equals(
1580
+ a:
1581
+ | GetLabelerRecordsResponse
1582
+ | PlainMessage<GetLabelerRecordsResponse>
1583
+ | undefined,
1584
+ b:
1585
+ | GetLabelerRecordsResponse
1586
+ | PlainMessage<GetLabelerRecordsResponse>
1587
+ | undefined,
1588
+ ): boolean {
1589
+ return proto3.util.equals(GetLabelerRecordsResponse, a, b)
1590
+ }
1591
+ }
1592
+
1477
1593
  /**
1478
1594
  * - Return follow uris where user A follows users B, C, D, …
1479
1595
  * - E.g. for viewer state on `getProfiles`
@@ -2595,6 +2711,16 @@ export class GetCountsForUsersResponse extends Message<GetCountsForUsersResponse
2595
2711
  */
2596
2712
  followers: number[] = []
2597
2713
 
2714
+ /**
2715
+ * @generated from field: repeated int32 lists = 5;
2716
+ */
2717
+ lists: number[] = []
2718
+
2719
+ /**
2720
+ * @generated from field: repeated int32 feeds = 6;
2721
+ */
2722
+ feeds: number[] = []
2723
+
2598
2724
  constructor(data?: PartialMessage<GetCountsForUsersResponse>) {
2599
2725
  super()
2600
2726
  proto3.util.initPartial(data, this)
@@ -2631,6 +2757,20 @@ export class GetCountsForUsersResponse extends Message<GetCountsForUsersResponse
2631
2757
  T: 5 /* ScalarType.INT32 */,
2632
2758
  repeated: true,
2633
2759
  },
2760
+ {
2761
+ no: 5,
2762
+ name: 'lists',
2763
+ kind: 'scalar',
2764
+ T: 5 /* ScalarType.INT32 */,
2765
+ repeated: true,
2766
+ },
2767
+ {
2768
+ no: 6,
2769
+ name: 'feeds',
2770
+ kind: 'scalar',
2771
+ T: 5 /* ScalarType.INT32 */,
2772
+ repeated: true,
2773
+ },
2634
2774
  ])
2635
2775
 
2636
2776
  static fromBinary(
@@ -3227,6 +3367,11 @@ export class ActorInfo extends Message<ActorInfo> {
3227
3367
  */
3228
3368
  tombstonedAt?: Timestamp
3229
3369
 
3370
+ /**
3371
+ * @generated from field: bool labeler = 7;
3372
+ */
3373
+ labeler = false
3374
+
3230
3375
  constructor(data?: PartialMessage<ActorInfo>) {
3231
3376
  super()
3232
3377
  proto3.util.initPartial(data, this)
@@ -3246,6 +3391,7 @@ export class ActorInfo extends Message<ActorInfo> {
3246
3391
  T: 9 /* ScalarType.STRING */,
3247
3392
  },
3248
3393
  { no: 6, name: 'tombstoned_at', kind: 'message', T: Timestamp },
3394
+ { no: 7, name: 'labeler', kind: 'scalar', T: 8 /* ScalarType.BOOL */ },
3249
3395
  ])
3250
3396
 
3251
3397
  static fromBinary(
package/src/util.ts ADDED
@@ -0,0 +1,44 @@
1
+ import { parseList } from 'structured-headers'
2
+
3
+ export type ParsedLabelers = {
4
+ dids: string[]
5
+ redact: Set<string>
6
+ }
7
+
8
+ export const parseLabelerHeader = (
9
+ header: string | undefined,
10
+ ): ParsedLabelers | null => {
11
+ if (!header) return null
12
+ const labelerDids = new Set<string>()
13
+ const redactDids = new Set<string>()
14
+ const parsed = parseList(header)
15
+ for (const item of parsed) {
16
+ const did = item[0].toString()
17
+ if (!did) {
18
+ return null
19
+ }
20
+ labelerDids.add(did)
21
+ const redact = item[1].get('redact')?.valueOf()
22
+ if (redact === true) {
23
+ redactDids.add(did)
24
+ }
25
+ }
26
+ return {
27
+ dids: [...labelerDids],
28
+ redact: redactDids,
29
+ }
30
+ }
31
+
32
+ export const defaultLabelerHeader = (dids: string[]): ParsedLabelers => {
33
+ return {
34
+ dids,
35
+ redact: new Set(dids),
36
+ }
37
+ }
38
+
39
+ export const formatLabelerHeader = (parsed: ParsedLabelers): string => {
40
+ const parts = parsed.dids.map((did) =>
41
+ parsed.redact.has(did) ? `${did};redact` : did,
42
+ )
43
+ return parts.join(',')
44
+ }
@@ -48,6 +48,10 @@ import {
48
48
  import { Label } from '../hydration/label'
49
49
  import { FeedItem, Post, Repost } from '../hydration/feed'
50
50
  import { RecordInfo } from '../hydration/util'
51
+ import {
52
+ LabelerView,
53
+ LabelerViewDetailed,
54
+ } from '../lexicon/types/app/bsky/labeler/defs'
51
55
  import { Notification } from '../proto/bsky_pb'
52
56
 
53
57
  export class Views {
@@ -57,7 +61,9 @@ export class Views {
57
61
  // ------------
58
62
 
59
63
  actorIsTakendown(did: string, state: HydrationState): boolean {
60
- return !!state.actors?.get(did)?.takedownRef
64
+ if (state.actors?.get(did)?.takedownRef) return true
65
+ if (state.labels?.get(did)?.isTakendown) return true
66
+ return false
61
67
  }
62
68
 
63
69
  viewerBlockExists(did: string, state: HydrationState): boolean {
@@ -98,6 +104,11 @@ export class Views {
98
104
  followersCount: profileAggs?.followers,
99
105
  followsCount: profileAggs?.follows,
100
106
  postsCount: profileAggs?.posts,
107
+ associated: {
108
+ lists: profileAggs?.lists,
109
+ feedgens: profileAggs?.feeds,
110
+ labeler: actor?.isLabeler,
111
+ },
101
112
  }
102
113
  }
103
114
 
@@ -125,8 +136,8 @@ export class Views {
125
136
  'self',
126
137
  ).toString()
127
138
  const labels = [
128
- ...(state.labels?.get(did) ?? []),
129
- ...(state.labels?.get(profileUri) ?? []),
139
+ ...(state.labels?.get(did)?.labels ?? []),
140
+ ...(state.labels?.get(profileUri)?.labels ?? []),
130
141
  ...this.selfLabels({
131
142
  uri: profileUri,
132
143
  cid: actor.profileCid?.toString(),
@@ -214,6 +225,7 @@ export class Views {
214
225
  return undefined
215
226
  }
216
227
  const listViewer = state.listViewers?.get(uri)
228
+ const labels = state.labels?.get(uri)?.labels ?? []
217
229
  const creator = new AtUri(uri).hostname
218
230
  return {
219
231
  uri,
@@ -228,6 +240,7 @@ export class Views {
228
240
  )
229
241
  : undefined,
230
242
  indexedAt: list.sortedAt.toISOString(),
243
+ labels,
231
244
  viewer: listViewer
232
245
  ? {
233
246
  muted: !!listViewer.viewerMuted,
@@ -258,6 +271,54 @@ export class Views {
258
271
  })
259
272
  }
260
273
 
274
+ labeler(did: string, state: HydrationState): LabelerView | undefined {
275
+ const labeler = state.labelers?.get(did)
276
+ if (!labeler) return
277
+ const creator = this.profile(did, state)
278
+ if (!creator) return
279
+ const viewer = state.labelerViewers?.get(did)
280
+ const aggs = state.labelerAggs?.get(did)
281
+
282
+ const uri = AtUri.make(did, ids.AppBskyLabelerService, 'self').toString()
283
+ const labels = [
284
+ ...(state.labels?.get(uri)?.labels ?? []),
285
+ ...this.selfLabels({
286
+ uri,
287
+ cid: labeler.cid.toString(),
288
+ record: labeler.record,
289
+ }),
290
+ ]
291
+
292
+ return {
293
+ uri,
294
+ cid: labeler.cid.toString(),
295
+ creator,
296
+ likeCount: aggs?.likes,
297
+ viewer: viewer
298
+ ? {
299
+ like: viewer.like,
300
+ }
301
+ : undefined,
302
+ indexedAt: labeler.sortedAt.toISOString(),
303
+ labels,
304
+ }
305
+ }
306
+
307
+ labelerDetailed(
308
+ did: string,
309
+ state: HydrationState,
310
+ ): LabelerViewDetailed | undefined {
311
+ const baseView = this.labeler(did, state)
312
+ if (!baseView) return
313
+ const record = state.labelers?.get(did)
314
+ if (!record) return
315
+
316
+ return {
317
+ ...baseView,
318
+ policies: record.record.policies,
319
+ }
320
+ }
321
+
261
322
  // Feed
262
323
  // ------------
263
324
 
@@ -290,6 +351,7 @@ export class Views {
290
351
  if (!creator) return
291
352
  const viewer = state.feedgenViewers?.get(uri)
292
353
  const aggs = state.feedgenAggs?.get(uri)
354
+ const labels = state.labels?.get(uri)?.labels ?? []
293
355
 
294
356
  return {
295
357
  uri,
@@ -307,6 +369,7 @@ export class Views {
307
369
  )
308
370
  : undefined,
309
371
  likeCount: aggs?.likes,
372
+ labels,
310
373
  viewer: viewer
311
374
  ? {
312
375
  like: viewer.like,
@@ -345,7 +408,7 @@ export class Views {
345
408
  parsedUri.rkey,
346
409
  ).toString()
347
410
  const labels = [
348
- ...(state.labels?.get(uri) ?? []),
411
+ ...(state.labels?.get(uri)?.labels ?? []),
349
412
  ...this.selfLabels({
350
413
  uri,
351
414
  cid: post.cid,
@@ -728,6 +791,11 @@ export class Views {
728
791
  if (!view) return this.embedNotFound(uri)
729
792
  view.$type = 'app.bsky.graph.defs#listView'
730
793
  return this.recordEmbedWrapper(view, withTypeTag)
794
+ } else if (parsedUri.collection === ids.AppBskyLabelerService) {
795
+ const view = this.labeler(parsedUri.hostname, state)
796
+ if (!view) return this.embedNotFound(uri)
797
+ view.$type = 'app.bsky.labeler.defs#labelerView'
798
+ return this.recordEmbedWrapper(view, withTypeTag)
731
799
  }
732
800
  return this.embedNotFound(uri)
733
801
  }
@@ -771,7 +839,8 @@ export class Views {
771
839
  }
772
840
  const rootUriStr: string = post?.record.reply?.root.uri ?? uri
773
841
  const gate = state.threadgates?.get(postToGateUri(rootUriStr))?.record
774
- if (!gate || !state.viewer) {
842
+ const viewer = state.ctx?.viewer
843
+ if (!gate || !viewer) {
775
844
  return undefined
776
845
  }
777
846
  const rootPost = state.posts?.get(rootUriStr)?.record
@@ -780,7 +849,7 @@ export class Views {
780
849
  canReply,
781
850
  allowFollowing,
782
851
  allowListUris = [],
783
- } = parseThreadGate(state.viewer, ownerDid, rootPost ?? null, gate)
852
+ } = parseThreadGate(viewer, ownerDid, rootPost ?? null, gate)
784
853
  if (canReply) {
785
854
  return false
786
855
  }
@@ -817,7 +886,7 @@ export class Views {
817
886
  recordInfo = state.follows?.get(notif.uri)
818
887
  }
819
888
  if (!recordInfo) return
820
- const labels = state.labels?.get(notif.uri) ?? []
889
+ const labels = state.labels?.get(notif.uri)?.labels ?? []
821
890
  const selfLabels = this.selfLabels({
822
891
  uri: notif.uri,
823
892
  cid: recordInfo.cid,
@@ -9,8 +9,6 @@ import {
9
9
  import {
10
10
  Main as RecordEmbed,
11
11
  View as RecordEmbedView,
12
- ViewBlocked as EmbedBlocked,
13
- ViewNotFound as EmbedNotFound,
14
12
  ViewRecord as PostEmbedView,
15
13
  } from '../lexicon/types/app/bsky/embed/record'
16
14
  import {
@@ -24,6 +22,7 @@ import {
24
22
  PostView,
25
23
  } from '../lexicon/types/app/bsky/feed/defs'
26
24
  import { ListView } from '../lexicon/types/app/bsky/graph/defs'
25
+ import { LabelerView } from '../lexicon/types/app/bsky/labeler/defs'
27
26
 
28
27
  export type {
29
28
  Main as ImagesEmbed,
@@ -69,4 +68,8 @@ export type EmbedView =
69
68
 
70
69
  export type MaybePostView = PostView | NotFoundPost | BlockedPost
71
70
 
72
- export type RecordEmbedViewInternal = PostEmbedView | GeneratorView | ListView
71
+ export type RecordEmbedViewInternal =
72
+ | PostEmbedView
73
+ | GeneratorView
74
+ | ListView
75
+ | LabelerView
@@ -99,6 +99,7 @@ Object {
99
99
  "did": "user(2)",
100
100
  "displayName": "All",
101
101
  "indexedAt": "1970-01-01T00:00:00.000Z",
102
+ "labels": Array [],
102
103
  "likeCount": 2,
103
104
  "uri": "record(1)",
104
105
  "viewer": Object {
@@ -168,6 +169,7 @@ Array [
168
169
  "did": "user(0)",
169
170
  "displayName": "Odd",
170
171
  "indexedAt": "1970-01-01T00:00:00.000Z",
172
+ "labels": Array [],
171
173
  "likeCount": 0,
172
174
  "uri": "record(0)",
173
175
  "viewer": Object {},
@@ -210,6 +212,7 @@ Array [
210
212
  "did": "user(0)",
211
213
  "displayName": "Needs Auth",
212
214
  "indexedAt": "1970-01-01T00:00:00.000Z",
215
+ "labels": Array [],
213
216
  "likeCount": 0,
214
217
  "uri": "record(4)",
215
218
  "viewer": Object {},
@@ -252,6 +255,7 @@ Array [
252
255
  "did": "user(0)",
253
256
  "displayName": "Bad Pagination",
254
257
  "indexedAt": "1970-01-01T00:00:00.000Z",
258
+ "labels": Array [],
255
259
  "likeCount": 0,
256
260
  "uri": "record(5)",
257
261
  "viewer": Object {},
@@ -294,6 +298,7 @@ Array [
294
298
  "did": "user(0)",
295
299
  "displayName": "Even",
296
300
  "indexedAt": "1970-01-01T00:00:00.000Z",
301
+ "labels": Array [],
297
302
  "likeCount": 0,
298
303
  "uri": "record(6)",
299
304
  "viewer": Object {},
@@ -336,6 +341,7 @@ Array [
336
341
  "did": "user(0)",
337
342
  "displayName": "All",
338
343
  "indexedAt": "1970-01-01T00:00:00.000Z",
344
+ "labels": Array [],
339
345
  "likeCount": 2,
340
346
  "uri": "record(7)",
341
347
  "viewer": Object {
@@ -1493,6 +1499,7 @@ Object {
1493
1499
  "did": "user(0)",
1494
1500
  "displayName": "All",
1495
1501
  "indexedAt": "1970-01-01T00:00:00.000Z",
1502
+ "labels": Array [],
1496
1503
  "likeCount": 2,
1497
1504
  "uri": "record(0)",
1498
1505
  "viewer": Object {
@@ -1543,6 +1550,7 @@ Object {
1543
1550
  "did": "user(0)",
1544
1551
  "displayName": "Even",
1545
1552
  "indexedAt": "1970-01-01T00:00:00.000Z",
1553
+ "labels": Array [],
1546
1554
  "likeCount": 0,
1547
1555
  "uri": "record(0)",
1548
1556
  "viewer": Object {},
@@ -1585,6 +1593,7 @@ Object {
1585
1593
  "did": "user(0)",
1586
1594
  "displayName": "All",
1587
1595
  "indexedAt": "1970-01-01T00:00:00.000Z",
1596
+ "labels": Array [],
1588
1597
  "likeCount": 2,
1589
1598
  "uri": "record(4)",
1590
1599
  "viewer": Object {
@@ -1637,6 +1646,7 @@ Object {
1637
1646
  "did": "user(0)",
1638
1647
  "displayName": "All",
1639
1648
  "indexedAt": "1970-01-01T00:00:00.000Z",
1649
+ "labels": Array [],
1640
1650
  "likeCount": 2,
1641
1651
  "uri": "record(0)",
1642
1652
  "viewer": Object {
@@ -1681,6 +1691,7 @@ Object {
1681
1691
  "did": "user(0)",
1682
1692
  "displayName": "Even",
1683
1693
  "indexedAt": "1970-01-01T00:00:00.000Z",
1694
+ "labels": Array [],
1684
1695
  "likeCount": 0,
1685
1696
  "uri": "record(5)",
1686
1697
  "viewer": Object {},
@@ -1723,6 +1734,7 @@ Object {
1723
1734
  "did": "user(0)",
1724
1735
  "displayName": "Bad Pagination",
1725
1736
  "indexedAt": "1970-01-01T00:00:00.000Z",
1737
+ "labels": Array [],
1726
1738
  "likeCount": 0,
1727
1739
  "uri": "record(6)",
1728
1740
  "viewer": Object {},
package/tests/_util.ts CHANGED
@@ -8,6 +8,11 @@ import {
8
8
  isThreadViewPost,
9
9
  } from '../src/lexicon/types/app/bsky/feed/defs'
10
10
  import { isViewRecord } from '../src/lexicon/types/app/bsky/embed/record'
11
+ import {
12
+ LabelerView,
13
+ isLabelerView,
14
+ isLabelerViewDetailed,
15
+ } from '../src/lexicon/types/app/bsky/labeler/defs'
11
16
 
12
17
  // Swap out identifiers and dates with stable
13
18
  // values for the purpose of snapshot testing
@@ -190,3 +195,19 @@ export const stripViewerFromThread = <T>(thread: T): T => {
190
195
  }
191
196
  return thread
192
197
  }
198
+
199
+ // @NOTE mutates
200
+ export const stripViewerFromLabeler = (
201
+ serviceUnknown: unknown,
202
+ ): LabelerView => {
203
+ if (
204
+ serviceUnknown?.['$type'] &&
205
+ !isLabelerView(serviceUnknown) &&
206
+ !isLabelerViewDetailed(serviceUnknown)
207
+ ) {
208
+ throw new Error('Expected mod service view')
209
+ }
210
+ const labeler = serviceUnknown as LabelerView
211
+ labeler.creator = stripViewer(labeler.creator)
212
+ return stripViewer(labeler)
213
+ }