@atproto/bsky 0.0.152 → 0.0.153
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 +7 -0
- package/dist/api/app/bsky/unspecced/getPostThreadHiddenV2.js +2 -1
- package/dist/api/app/bsky/unspecced/getPostThreadHiddenV2.js.map +1 -1
- package/dist/api/com/atproto/repo/getRecord.d.ts.map +1 -1
- package/dist/api/com/atproto/repo/getRecord.js +1 -1
- package/dist/api/com/atproto/repo/getRecord.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -0
- package/dist/config.js.map +1 -1
- package/dist/data-plane/server/db/migrations/20250528T221913281Z-add-record-tags.d.ts +4 -0
- package/dist/data-plane/server/db/migrations/20250528T221913281Z-add-record-tags.d.ts.map +1 -0
- package/dist/data-plane/server/db/migrations/20250528T221913281Z-add-record-tags.js +11 -0
- package/dist/data-plane/server/db/migrations/20250528T221913281Z-add-record-tags.js.map +1 -0
- package/dist/data-plane/server/db/migrations/index.d.ts +1 -0
- package/dist/data-plane/server/db/migrations/index.d.ts.map +1 -1
- package/dist/data-plane/server/db/migrations/index.js +2 -1
- package/dist/data-plane/server/db/migrations/index.js.map +1 -1
- package/dist/data-plane/server/db/tables/record.d.ts +1 -0
- package/dist/data-plane/server/db/tables/record.d.ts.map +1 -1
- package/dist/data-plane/server/db/tables/record.js.map +1 -1
- package/dist/data-plane/server/routes/records.d.ts.map +1 -1
- package/dist/data-plane/server/routes/records.js +1 -0
- package/dist/data-plane/server/routes/records.js.map +1 -1
- package/dist/hydration/feed.d.ts +1 -0
- package/dist/hydration/feed.d.ts.map +1 -1
- package/dist/hydration/feed.js +2 -0
- package/dist/hydration/feed.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lexicon/lexicons.d.ts +10 -0
- package/dist/lexicon/lexicons.d.ts.map +1 -1
- package/dist/lexicon/lexicons.js +5 -0
- package/dist/lexicon/lexicons.js.map +1 -1
- package/dist/lexicon/types/app/bsky/unspecced/getPostThreadHiddenV2.d.ts +2 -0
- package/dist/lexicon/types/app/bsky/unspecced/getPostThreadHiddenV2.d.ts.map +1 -1
- package/dist/lexicon/types/app/bsky/unspecced/getPostThreadHiddenV2.js.map +1 -1
- package/dist/proto/bsky_pb.d.ts +4 -0
- package/dist/proto/bsky_pb.d.ts.map +1 -1
- package/dist/proto/bsky_pb.js +16 -0
- package/dist/proto/bsky_pb.js.map +1 -1
- package/dist/proto/bsync_connect.d.ts +19 -1
- package/dist/proto/bsync_connect.d.ts.map +1 -1
- package/dist/proto/bsync_connect.js +18 -0
- package/dist/proto/bsync_connect.js.map +1 -1
- package/dist/proto/bsync_pb.d.ts +150 -0
- package/dist/proto/bsync_pb.d.ts.map +1 -1
- package/dist/proto/bsync_pb.js +401 -1
- package/dist/proto/bsync_pb.js.map +1 -1
- package/dist/views/index.d.ts +6 -1
- package/dist/views/index.d.ts.map +1 -1
- package/dist/views/index.js +58 -22
- package/dist/views/index.js.map +1 -1
- package/dist/views/threads-v2.d.ts +4 -1
- package/dist/views/threads-v2.d.ts.map +1 -1
- package/dist/views/threads-v2.js +50 -25
- package/dist/views/threads-v2.js.map +1 -1
- package/package.json +5 -5
- package/proto/bsky.proto +1 -0
- package/src/api/app/bsky/unspecced/getPostThreadHiddenV2.ts +2 -1
- package/src/api/com/atproto/repo/getRecord.ts +4 -1
- package/src/config.ts +15 -0
- package/src/data-plane/server/db/migrations/20250528T221913281Z-add-record-tags.ts +9 -0
- package/src/data-plane/server/db/migrations/index.ts +1 -0
- package/src/data-plane/server/db/tables/record.ts +1 -0
- package/src/data-plane/server/routes/records.ts +1 -0
- package/src/hydration/feed.ts +3 -0
- package/src/index.ts +2 -0
- package/src/lexicon/lexicons.ts +6 -0
- package/src/lexicon/types/app/bsky/unspecced/getPostThreadHiddenV2.ts +2 -0
- package/src/proto/bsky_pb.ts +12 -0
- package/src/proto/bsync_connect.ts +22 -0
- package/src/proto/bsync_pb.ts +355 -0
- package/src/views/index.ts +90 -52
- package/src/views/threads-v2.ts +67 -37
- package/tests/seed/thread-v2.ts +131 -32
- package/tests/views/thread-v2.test.ts +139 -27
- package/tsconfig.build.tsbuildinfo +1 -1
package/src/views/index.ts
CHANGED
|
@@ -130,11 +130,15 @@ export class Views {
|
|
|
130
130
|
public imgUriBuilder: ImageUriBuilder = this.opts.imgUriBuilder
|
|
131
131
|
public videoUriBuilder: VideoUriBuilder = this.opts.videoUriBuilder
|
|
132
132
|
public indexedAtEpoch: Date | undefined = this.opts.indexedAtEpoch
|
|
133
|
+
private threadTagsBumpDown: readonly string[] = this.opts.threadTagsBumpDown
|
|
134
|
+
private threadTagsHide: readonly string[] = this.opts.threadTagsHide
|
|
133
135
|
constructor(
|
|
134
136
|
private opts: {
|
|
135
137
|
imgUriBuilder: ImageUriBuilder
|
|
136
138
|
videoUriBuilder: VideoUriBuilder
|
|
137
139
|
indexedAtEpoch: Date | undefined
|
|
140
|
+
threadTagsBumpDown: readonly string[]
|
|
141
|
+
threadTagsHide: readonly string[]
|
|
138
142
|
},
|
|
139
143
|
) {}
|
|
140
144
|
|
|
@@ -1248,6 +1252,7 @@ export class Views {
|
|
|
1248
1252
|
below,
|
|
1249
1253
|
depth: 1,
|
|
1250
1254
|
branchingFactor,
|
|
1255
|
+
prioritizeFollowedUsers,
|
|
1251
1256
|
},
|
|
1252
1257
|
state,
|
|
1253
1258
|
)
|
|
@@ -1263,6 +1268,7 @@ export class Views {
|
|
|
1263
1268
|
repliesAllowance: Infinity, // While we don't have pagination.
|
|
1264
1269
|
uri: anchorUri,
|
|
1265
1270
|
}),
|
|
1271
|
+
tags: post.tags,
|
|
1266
1272
|
hasOPLike: !!state.threadContexts?.get(postView.uri)?.like,
|
|
1267
1273
|
parent,
|
|
1268
1274
|
replies,
|
|
@@ -1275,7 +1281,8 @@ export class Views {
|
|
|
1275
1281
|
sort,
|
|
1276
1282
|
prioritizeFollowedUsers,
|
|
1277
1283
|
viewer: state.ctx?.viewer ?? null,
|
|
1278
|
-
|
|
1284
|
+
threadTagsBumpDown: this.threadTagsBumpDown,
|
|
1285
|
+
threadTagsHide: this.threadTagsHide,
|
|
1279
1286
|
})
|
|
1280
1287
|
|
|
1281
1288
|
return {
|
|
@@ -1392,6 +1399,7 @@ export class Views {
|
|
|
1392
1399
|
postView,
|
|
1393
1400
|
uri,
|
|
1394
1401
|
}),
|
|
1402
|
+
tags: post.tags,
|
|
1395
1403
|
hasOPLike: !!state.threadContexts?.get(postView.uri)?.like,
|
|
1396
1404
|
parent,
|
|
1397
1405
|
replies: undefined,
|
|
@@ -1410,6 +1418,7 @@ export class Views {
|
|
|
1410
1418
|
below,
|
|
1411
1419
|
depth,
|
|
1412
1420
|
branchingFactor,
|
|
1421
|
+
prioritizeFollowedUsers,
|
|
1413
1422
|
}: {
|
|
1414
1423
|
parentUri: string
|
|
1415
1424
|
isOPThread: boolean
|
|
@@ -1419,6 +1428,7 @@ export class Views {
|
|
|
1419
1428
|
below: number
|
|
1420
1429
|
depth: number
|
|
1421
1430
|
branchingFactor: number
|
|
1431
|
+
prioritizeFollowedUsers: boolean
|
|
1422
1432
|
},
|
|
1423
1433
|
state: HydrationState,
|
|
1424
1434
|
): { replies: ThreadTreeVisible[] | undefined; hasHiddenReplies: boolean } {
|
|
@@ -1430,23 +1440,22 @@ export class Views {
|
|
|
1430
1440
|
const childrenUris = childrenByParentUri[parentUri] ?? []
|
|
1431
1441
|
let hasHiddenReplies = false
|
|
1432
1442
|
const replies = mapDefined(childrenUris, (uri) => {
|
|
1433
|
-
const replyInclusion = this.checkThreadV2ReplyInclusion(
|
|
1443
|
+
const replyInclusion = this.checkThreadV2ReplyInclusion({
|
|
1434
1444
|
uri,
|
|
1435
1445
|
rootUri,
|
|
1436
1446
|
state,
|
|
1437
|
-
)
|
|
1447
|
+
})
|
|
1438
1448
|
if (!replyInclusion) {
|
|
1439
1449
|
return undefined
|
|
1440
1450
|
}
|
|
1441
|
-
const { authorDid, postView } = replyInclusion
|
|
1451
|
+
const { authorDid, post, postView } = replyInclusion
|
|
1442
1452
|
|
|
1443
1453
|
// Hidden.
|
|
1444
|
-
const {
|
|
1445
|
-
{ rootUri, uri },
|
|
1454
|
+
const { isHidden } = this.isHiddenThreadPost(
|
|
1455
|
+
{ post, postView, prioritizeFollowedUsers, rootUri, uri },
|
|
1446
1456
|
state,
|
|
1447
1457
|
)
|
|
1448
|
-
|
|
1449
|
-
if (hiddenByThreadgate || mutedByViewer) {
|
|
1458
|
+
if (isHidden) {
|
|
1450
1459
|
// Only care about anchor replies
|
|
1451
1460
|
if (depth === 1) {
|
|
1452
1461
|
hasHiddenReplies = true
|
|
@@ -1466,6 +1475,7 @@ export class Views {
|
|
|
1466
1475
|
below,
|
|
1467
1476
|
depth: depth + 1,
|
|
1468
1477
|
branchingFactor,
|
|
1478
|
+
prioritizeFollowedUsers,
|
|
1469
1479
|
},
|
|
1470
1480
|
state,
|
|
1471
1481
|
)
|
|
@@ -1482,6 +1492,7 @@ export class Views {
|
|
|
1482
1492
|
repliesAllowance,
|
|
1483
1493
|
uri,
|
|
1484
1494
|
}),
|
|
1495
|
+
tags: post.tags,
|
|
1485
1496
|
hasOPLike: !!state.threadContexts?.get(postView.uri)?.like,
|
|
1486
1497
|
parent: undefined,
|
|
1487
1498
|
replies: nestedReplies,
|
|
@@ -1591,9 +1602,11 @@ export class Views {
|
|
|
1591
1602
|
{
|
|
1592
1603
|
below,
|
|
1593
1604
|
branchingFactor,
|
|
1605
|
+
prioritizeFollowedUsers,
|
|
1594
1606
|
}: {
|
|
1595
1607
|
below: number
|
|
1596
1608
|
branchingFactor: number
|
|
1609
|
+
prioritizeFollowedUsers: boolean
|
|
1597
1610
|
},
|
|
1598
1611
|
): ThreadHiddenItem[] {
|
|
1599
1612
|
const { anchor: anchorUri, uris } = skeleton
|
|
@@ -1628,6 +1641,7 @@ export class Views {
|
|
|
1628
1641
|
childrenByParentUri,
|
|
1629
1642
|
below,
|
|
1630
1643
|
depth: 1,
|
|
1644
|
+
prioritizeFollowedUsers,
|
|
1631
1645
|
},
|
|
1632
1646
|
state,
|
|
1633
1647
|
),
|
|
@@ -1638,7 +1652,8 @@ export class Views {
|
|
|
1638
1652
|
branchingFactor,
|
|
1639
1653
|
prioritizeFollowedUsers: false,
|
|
1640
1654
|
viewer: state.ctx?.viewer ?? null,
|
|
1641
|
-
|
|
1655
|
+
threadTagsBumpDown: this.threadTagsBumpDown,
|
|
1656
|
+
threadTagsHide: this.threadTagsHide,
|
|
1642
1657
|
})
|
|
1643
1658
|
}
|
|
1644
1659
|
|
|
@@ -1649,12 +1664,14 @@ export class Views {
|
|
|
1649
1664
|
childrenByParentUri,
|
|
1650
1665
|
below,
|
|
1651
1666
|
depth,
|
|
1667
|
+
prioritizeFollowedUsers,
|
|
1652
1668
|
}: {
|
|
1653
1669
|
parentUri: string
|
|
1654
1670
|
rootUri: string
|
|
1655
1671
|
childrenByParentUri: Record<string, string[]>
|
|
1656
1672
|
below: number
|
|
1657
1673
|
depth: number
|
|
1674
|
+
prioritizeFollowedUsers: boolean
|
|
1658
1675
|
},
|
|
1659
1676
|
state: HydrationState,
|
|
1660
1677
|
): ThreadHiddenPostNode[] | undefined {
|
|
@@ -1665,23 +1682,23 @@ export class Views {
|
|
|
1665
1682
|
|
|
1666
1683
|
const childrenUris = childrenByParentUri[parentUri] ?? []
|
|
1667
1684
|
return mapDefined(childrenUris, (uri) => {
|
|
1668
|
-
const replyInclusion = this.checkThreadV2ReplyInclusion(
|
|
1685
|
+
const replyInclusion = this.checkThreadV2ReplyInclusion({
|
|
1669
1686
|
uri,
|
|
1670
1687
|
rootUri,
|
|
1671
1688
|
state,
|
|
1672
|
-
)
|
|
1689
|
+
})
|
|
1673
1690
|
if (!replyInclusion) {
|
|
1674
1691
|
return undefined
|
|
1675
1692
|
}
|
|
1676
|
-
const { postView } = replyInclusion
|
|
1693
|
+
const { post, postView } = replyInclusion
|
|
1677
1694
|
|
|
1678
1695
|
// Hidden.
|
|
1679
|
-
const { hiddenByThreadgate, mutedByViewer } =
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
if (
|
|
1696
|
+
const { isHidden, hiddenByThreadgate, mutedByViewer } =
|
|
1697
|
+
this.isHiddenThreadPost(
|
|
1698
|
+
{ post, postView, rootUri, prioritizeFollowedUsers, uri },
|
|
1699
|
+
state,
|
|
1700
|
+
)
|
|
1701
|
+
if (isHidden) {
|
|
1685
1702
|
// Only show hidden anchor replies, not all hidden.
|
|
1686
1703
|
if (depth > 1) {
|
|
1687
1704
|
return undefined
|
|
@@ -1699,23 +1716,23 @@ export class Views {
|
|
|
1699
1716
|
childrenByParentUri,
|
|
1700
1717
|
below,
|
|
1701
1718
|
depth: depth + 1,
|
|
1719
|
+
prioritizeFollowedUsers,
|
|
1702
1720
|
},
|
|
1703
1721
|
state,
|
|
1704
1722
|
)
|
|
1705
1723
|
|
|
1706
|
-
const item = this.threadHiddenV2ItemPost(
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
state,
|
|
1714
|
-
)
|
|
1724
|
+
const item = this.threadHiddenV2ItemPost({
|
|
1725
|
+
depth,
|
|
1726
|
+
hiddenByThreadgate,
|
|
1727
|
+
mutedByViewer,
|
|
1728
|
+
postView,
|
|
1729
|
+
uri,
|
|
1730
|
+
})
|
|
1715
1731
|
|
|
1716
1732
|
const tree: ThreadHiddenPostNode = {
|
|
1717
1733
|
type: 'hiddenPost',
|
|
1718
1734
|
item: item,
|
|
1735
|
+
tags: post.tags,
|
|
1719
1736
|
replies,
|
|
1720
1737
|
}
|
|
1721
1738
|
|
|
@@ -1739,25 +1756,19 @@ export class Views {
|
|
|
1739
1756
|
}
|
|
1740
1757
|
}
|
|
1741
1758
|
|
|
1742
|
-
private threadHiddenV2ItemPost(
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
): ThreadHiddenPostNode['item'] {
|
|
1756
|
-
const { hiddenByThreadgate, mutedByViewer } = this.isHiddenThreadPost(
|
|
1757
|
-
{ rootUri, uri },
|
|
1758
|
-
state,
|
|
1759
|
-
)
|
|
1760
|
-
|
|
1759
|
+
private threadHiddenV2ItemPost({
|
|
1760
|
+
depth,
|
|
1761
|
+
hiddenByThreadgate,
|
|
1762
|
+
mutedByViewer,
|
|
1763
|
+
postView,
|
|
1764
|
+
uri,
|
|
1765
|
+
}: {
|
|
1766
|
+
depth: number
|
|
1767
|
+
hiddenByThreadgate: boolean
|
|
1768
|
+
mutedByViewer: boolean
|
|
1769
|
+
postView: PostView
|
|
1770
|
+
uri: string
|
|
1771
|
+
}): ThreadHiddenPostNode['item'] {
|
|
1761
1772
|
const base = this.threadHiddenV2ItemPostAnchor({ depth, uri })
|
|
1762
1773
|
return {
|
|
1763
1774
|
...base,
|
|
@@ -1770,11 +1781,19 @@ export class Views {
|
|
|
1770
1781
|
}
|
|
1771
1782
|
}
|
|
1772
1783
|
|
|
1773
|
-
private checkThreadV2ReplyInclusion(
|
|
1774
|
-
uri
|
|
1775
|
-
rootUri
|
|
1776
|
-
state
|
|
1777
|
-
|
|
1784
|
+
private checkThreadV2ReplyInclusion({
|
|
1785
|
+
uri,
|
|
1786
|
+
rootUri,
|
|
1787
|
+
state,
|
|
1788
|
+
}: {
|
|
1789
|
+
uri: string
|
|
1790
|
+
rootUri: string
|
|
1791
|
+
state: HydrationState
|
|
1792
|
+
}): {
|
|
1793
|
+
authorDid: string
|
|
1794
|
+
post: Post
|
|
1795
|
+
postView: PostView
|
|
1796
|
+
} | null {
|
|
1778
1797
|
// Not found.
|
|
1779
1798
|
const post = state.posts?.get(uri)
|
|
1780
1799
|
if (post?.violatesThreadGate) {
|
|
@@ -1806,24 +1825,41 @@ export class Views {
|
|
|
1806
1825
|
return null
|
|
1807
1826
|
}
|
|
1808
1827
|
|
|
1809
|
-
return { authorDid, postView }
|
|
1828
|
+
return { authorDid, post, postView }
|
|
1810
1829
|
}
|
|
1811
1830
|
|
|
1812
1831
|
private isHiddenThreadPost(
|
|
1813
1832
|
{
|
|
1833
|
+
post,
|
|
1834
|
+
postView,
|
|
1835
|
+
prioritizeFollowedUsers,
|
|
1814
1836
|
rootUri,
|
|
1815
1837
|
uri,
|
|
1816
1838
|
}: {
|
|
1839
|
+
post: Post
|
|
1840
|
+
postView: PostView
|
|
1841
|
+
prioritizeFollowedUsers: boolean
|
|
1817
1842
|
rootUri: string
|
|
1818
1843
|
uri: string
|
|
1819
1844
|
},
|
|
1820
1845
|
state: HydrationState,
|
|
1821
1846
|
): {
|
|
1847
|
+
isHidden: boolean
|
|
1848
|
+
hiddenByTag: boolean
|
|
1822
1849
|
hiddenByThreadgate: boolean
|
|
1823
1850
|
mutedByViewer: boolean
|
|
1824
1851
|
} {
|
|
1852
|
+
const opDid = creatorFromUri(rootUri)
|
|
1825
1853
|
const authorDid = creatorFromUri(uri)
|
|
1826
1854
|
|
|
1855
|
+
const showBecauseFollowing =
|
|
1856
|
+
prioritizeFollowedUsers && !!postView.author.viewer?.following
|
|
1857
|
+
const hiddenByTag =
|
|
1858
|
+
authorDid !== opDid &&
|
|
1859
|
+
authorDid !== state.ctx?.viewer &&
|
|
1860
|
+
!showBecauseFollowing &&
|
|
1861
|
+
this.threadTagsHide.some((t) => post.tags.has(t))
|
|
1862
|
+
|
|
1827
1863
|
const hiddenByThreadgate =
|
|
1828
1864
|
state.ctx?.viewer !== authorDid &&
|
|
1829
1865
|
this.replyIsHiddenByThreadgate(uri, rootUri, state)
|
|
@@ -1831,6 +1867,8 @@ export class Views {
|
|
|
1831
1867
|
const mutedByViewer = this.viewerMuteExists(authorDid, state)
|
|
1832
1868
|
|
|
1833
1869
|
return {
|
|
1870
|
+
isHidden: hiddenByTag || hiddenByThreadgate || mutedByViewer,
|
|
1871
|
+
hiddenByTag,
|
|
1834
1872
|
hiddenByThreadgate,
|
|
1835
1873
|
mutedByViewer,
|
|
1836
1874
|
}
|
package/src/views/threads-v2.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { validateRecord as validatePostRecord } from '../lexicon/types/app/bsky/
|
|
|
4
4
|
import {
|
|
5
5
|
ThreadHiddenItem,
|
|
6
6
|
ThreadHiddenItemPost,
|
|
7
|
-
isThreadHiddenItemPost,
|
|
8
7
|
} from '../lexicon/types/app/bsky/unspecced/getPostThreadHiddenV2'
|
|
9
8
|
import {
|
|
10
9
|
QueryParams as GetPostThreadV2QueryParams,
|
|
@@ -59,6 +58,7 @@ type ThreadNotFoundNode = {
|
|
|
59
58
|
type ThreadPostNode = {
|
|
60
59
|
type: 'post'
|
|
61
60
|
item: ThreadItemValuePost
|
|
61
|
+
tags: Set<string>
|
|
62
62
|
hasOPLike: boolean
|
|
63
63
|
parent: ThreadTree | undefined
|
|
64
64
|
replies: ThreadTree[] | undefined
|
|
@@ -87,6 +87,7 @@ export type ThreadHiddenAnchorPostNode = {
|
|
|
87
87
|
export type ThreadHiddenPostNode = {
|
|
88
88
|
type: 'hiddenPost'
|
|
89
89
|
item: ThreadHiddenItemValuePost
|
|
90
|
+
tags: Set<string>
|
|
90
91
|
replies: ThreadHiddenPostNode[] | undefined
|
|
91
92
|
}
|
|
92
93
|
|
|
@@ -117,11 +118,12 @@ export function sortTrimFlattenThreadTree<
|
|
|
117
118
|
|
|
118
119
|
type SortTrimFlattenOptions = {
|
|
119
120
|
branchingFactor: GetPostThreadV2QueryParams['branchingFactor']
|
|
120
|
-
fetchedAt: number
|
|
121
121
|
opDid: string
|
|
122
122
|
prioritizeFollowedUsers: boolean
|
|
123
123
|
sort?: GetPostThreadV2QueryParams['sort']
|
|
124
124
|
viewer: HydrateCtx['viewer']
|
|
125
|
+
threadTagsBumpDown: readonly string[]
|
|
126
|
+
threadTagsHide: readonly string[]
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
const isPostRecord = asPredicate(validatePostRecord)
|
|
@@ -136,15 +138,6 @@ function sortTrimThreadTree(
|
|
|
136
138
|
}
|
|
137
139
|
const node: ThreadNodeWithReplies = n
|
|
138
140
|
|
|
139
|
-
const {
|
|
140
|
-
branchingFactor,
|
|
141
|
-
fetchedAt,
|
|
142
|
-
opDid,
|
|
143
|
-
prioritizeFollowedUsers,
|
|
144
|
-
sort,
|
|
145
|
-
viewer,
|
|
146
|
-
} = opts
|
|
147
|
-
|
|
148
141
|
if (node.replies) {
|
|
149
142
|
node.replies.sort((an: ThreadTree, bn: ThreadTree) => {
|
|
150
143
|
if (!isPostNode(an)) {
|
|
@@ -168,19 +161,10 @@ function sortTrimThreadTree(
|
|
|
168
161
|
|
|
169
162
|
// Trimming: after sorting, apply branching factor to all levels of replies except the anchor direct replies.
|
|
170
163
|
if (node.item.depth !== 0) {
|
|
171
|
-
node.replies = node.replies.slice(0, branchingFactor)
|
|
164
|
+
node.replies = node.replies.slice(0, opts.branchingFactor)
|
|
172
165
|
}
|
|
173
166
|
|
|
174
|
-
node.replies.forEach((reply) =>
|
|
175
|
-
sortTrimThreadTree(reply, {
|
|
176
|
-
branchingFactor,
|
|
177
|
-
fetchedAt,
|
|
178
|
-
opDid,
|
|
179
|
-
prioritizeFollowedUsers,
|
|
180
|
-
sort,
|
|
181
|
-
viewer,
|
|
182
|
-
}),
|
|
183
|
-
)
|
|
167
|
+
node.replies.forEach((reply) => sortTrimThreadTree(reply, opts))
|
|
184
168
|
}
|
|
185
169
|
|
|
186
170
|
return node
|
|
@@ -191,19 +175,30 @@ function applyBumping(
|
|
|
191
175
|
bNode: ThreadMaybeHiddenPostNode,
|
|
192
176
|
opts: SortTrimFlattenOptions,
|
|
193
177
|
): number | null {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
178
|
+
if (!isPostNode(aNode)) {
|
|
179
|
+
return null
|
|
180
|
+
}
|
|
181
|
+
if (!isPostNode(bNode)) {
|
|
182
|
+
return null
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const {
|
|
186
|
+
opDid,
|
|
187
|
+
prioritizeFollowedUsers,
|
|
188
|
+
viewer,
|
|
189
|
+
threadTagsBumpDown,
|
|
190
|
+
threadTagsHide,
|
|
191
|
+
} = opts
|
|
197
192
|
|
|
198
193
|
type BumpDirection = 'up' | 'down'
|
|
199
|
-
type BumpPredicateFn = (i:
|
|
194
|
+
type BumpPredicateFn = (i: ThreadMaybeHiddenPostNode) => boolean
|
|
200
195
|
|
|
201
196
|
const maybeBump = (
|
|
202
197
|
bump: BumpDirection,
|
|
203
198
|
predicateFn: BumpPredicateFn,
|
|
204
199
|
): number | null => {
|
|
205
|
-
const aPredicate = predicateFn(
|
|
206
|
-
const bPredicate = predicateFn(
|
|
200
|
+
const aPredicate = predicateFn(aNode)
|
|
201
|
+
const bPredicate = predicateFn(bNode)
|
|
207
202
|
if (aPredicate && bPredicate) {
|
|
208
203
|
return applySorting(aNode, bNode, opts)
|
|
209
204
|
} else if (aPredicate) {
|
|
@@ -218,21 +213,56 @@ function applyBumping(
|
|
|
218
213
|
// Bumps-up applied first make the item appear higher in the list than later bumps-up.
|
|
219
214
|
// Bumps-down applied first make the item appear lower in the list than later bumps-down.
|
|
220
215
|
const bumps: [BumpDirection, BumpPredicateFn][] = [
|
|
216
|
+
/*
|
|
217
|
+
General bumps.
|
|
218
|
+
*/
|
|
221
219
|
// OP replies.
|
|
222
|
-
['up', (i) => i.post.author.did === opDid],
|
|
220
|
+
['up', (i) => i.item.value.post.author.did === opDid],
|
|
223
221
|
// Viewer replies.
|
|
224
|
-
['up', (i) => i.post.author.did === viewer],
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
222
|
+
['up', (i) => i.item.value.post.author.did === viewer],
|
|
223
|
+
|
|
224
|
+
/*
|
|
225
|
+
Bumps within visible replies.
|
|
226
|
+
*/
|
|
227
|
+
// Followers posts.
|
|
228
|
+
[
|
|
229
|
+
'up',
|
|
230
|
+
(i) =>
|
|
231
|
+
i.type === 'post' &&
|
|
232
|
+
prioritizeFollowedUsers &&
|
|
233
|
+
!!i.item.value.post.author.viewer?.following,
|
|
234
|
+
],
|
|
235
|
+
// Bump-down tags.
|
|
236
|
+
[
|
|
237
|
+
'down',
|
|
238
|
+
(i) => i.type === 'post' && threadTagsBumpDown.some((t) => i.tags.has(t)),
|
|
239
|
+
],
|
|
229
240
|
// Pushpin-only.
|
|
230
241
|
[
|
|
231
242
|
'down',
|
|
232
|
-
(i) =>
|
|
243
|
+
(i) =>
|
|
244
|
+
i.type === 'post' &&
|
|
245
|
+
isPostRecord(i.item.value.post.record) &&
|
|
246
|
+
i.item.value.post.record.text.trim() === '📌',
|
|
233
247
|
],
|
|
234
|
-
|
|
235
|
-
|
|
248
|
+
|
|
249
|
+
/*
|
|
250
|
+
Bumps within hidden replies.
|
|
251
|
+
This determines the order of hidden replies:
|
|
252
|
+
1. hidden by threadgate.
|
|
253
|
+
2. hidden by tags.
|
|
254
|
+
3. muted by viewer.
|
|
255
|
+
*/
|
|
256
|
+
// Muted account by the viewer.
|
|
257
|
+
['down', (i) => i.type === 'hiddenPost' && i.item.value.mutedByViewer],
|
|
258
|
+
// Hidden by tags.
|
|
259
|
+
[
|
|
260
|
+
'down',
|
|
261
|
+
(i) =>
|
|
262
|
+
i.type === 'hiddenPost' && threadTagsHide.some((t) => i.tags.has(t)),
|
|
263
|
+
],
|
|
264
|
+
// Hidden by threadgate.
|
|
265
|
+
['down', (i) => i.type === 'hiddenPost' && i.item.value.hiddenByThreadgate],
|
|
236
266
|
]
|
|
237
267
|
|
|
238
268
|
for (const [bump, predicateFn] of bumps) {
|