@atproto/bsky 0.0.193 → 0.0.195

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 (77) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/api/app/bsky/feed/searchPosts.d.ts.map +1 -1
  3. package/dist/api/app/bsky/feed/searchPosts.js +43 -12
  4. package/dist/api/app/bsky/feed/searchPosts.js.map +1 -1
  5. package/dist/api/app/bsky/unspecced/getPostThreadOtherV2.js +1 -2
  6. package/dist/api/app/bsky/unspecced/getPostThreadOtherV2.js.map +1 -1
  7. package/dist/api/app/bsky/unspecced/getPostThreadV2.js +0 -1
  8. package/dist/api/app/bsky/unspecced/getPostThreadV2.js.map +1 -1
  9. package/dist/auth-verifier.d.ts +1 -0
  10. package/dist/auth-verifier.d.ts.map +1 -1
  11. package/dist/auth-verifier.js +4 -0
  12. package/dist/auth-verifier.js.map +1 -1
  13. package/dist/config.d.ts +2 -0
  14. package/dist/config.d.ts.map +1 -1
  15. package/dist/config.js +5 -0
  16. package/dist/config.js.map +1 -1
  17. package/dist/data-plane/server/routes/search.d.ts.map +1 -1
  18. package/dist/data-plane/server/routes/search.js +15 -1
  19. package/dist/data-plane/server/routes/search.js.map +1 -1
  20. package/dist/data-plane/server/util.d.ts +7 -0
  21. package/dist/data-plane/server/util.d.ts.map +1 -1
  22. package/dist/data-plane/server/util.js +38 -1
  23. package/dist/data-plane/server/util.js.map +1 -1
  24. package/dist/lexicon/index.d.ts +2 -0
  25. package/dist/lexicon/index.d.ts.map +1 -1
  26. package/dist/lexicon/index.js +4 -0
  27. package/dist/lexicon/index.js.map +1 -1
  28. package/dist/lexicon/lexicons.d.ts +106 -28
  29. package/dist/lexicon/lexicons.d.ts.map +1 -1
  30. package/dist/lexicon/lexicons.js +56 -14
  31. package/dist/lexicon/lexicons.js.map +1 -1
  32. package/dist/lexicon/types/app/bsky/actor/defs.d.ts +0 -2
  33. package/dist/lexicon/types/app/bsky/actor/defs.d.ts.map +1 -1
  34. package/dist/lexicon/types/app/bsky/actor/defs.js.map +1 -1
  35. package/dist/lexicon/types/app/bsky/graph/follow.d.ts +2 -0
  36. package/dist/lexicon/types/app/bsky/graph/follow.d.ts.map +1 -1
  37. package/dist/lexicon/types/app/bsky/graph/follow.js.map +1 -1
  38. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadOtherV2.d.ts +0 -2
  39. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadOtherV2.d.ts.map +1 -1
  40. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadOtherV2.js.map +1 -1
  41. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadV2.d.ts +0 -2
  42. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadV2.d.ts.map +1 -1
  43. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadV2.js.map +1 -1
  44. package/dist/lexicon/types/com/atproto/lexicon/resolveLexicon.d.ts +28 -0
  45. package/dist/lexicon/types/com/atproto/lexicon/resolveLexicon.d.ts.map +1 -0
  46. package/dist/lexicon/types/com/atproto/lexicon/resolveLexicon.js +7 -0
  47. package/dist/lexicon/types/com/atproto/lexicon/resolveLexicon.js.map +1 -0
  48. package/dist/views/index.d.ts +2 -4
  49. package/dist/views/index.d.ts.map +1 -1
  50. package/dist/views/index.js +8 -14
  51. package/dist/views/index.js.map +1 -1
  52. package/dist/views/threads-v2.d.ts +0 -1
  53. package/dist/views/threads-v2.d.ts.map +1 -1
  54. package/dist/views/threads-v2.js +2 -4
  55. package/dist/views/threads-v2.js.map +1 -1
  56. package/package.json +5 -5
  57. package/src/api/app/bsky/feed/searchPosts.ts +51 -10
  58. package/src/api/app/bsky/unspecced/getPostThreadOtherV2.ts +1 -2
  59. package/src/api/app/bsky/unspecced/getPostThreadV2.ts +0 -1
  60. package/src/auth-verifier.ts +5 -0
  61. package/src/config.ts +8 -0
  62. package/src/data-plane/server/routes/search.ts +18 -1
  63. package/src/data-plane/server/util.ts +51 -0
  64. package/src/lexicon/index.ts +13 -0
  65. package/src/lexicon/lexicons.ts +56 -16
  66. package/src/lexicon/types/app/bsky/actor/defs.ts +0 -2
  67. package/src/lexicon/types/app/bsky/graph/follow.ts +2 -0
  68. package/src/lexicon/types/app/bsky/unspecced/getPostThreadOtherV2.ts +0 -2
  69. package/src/lexicon/types/app/bsky/unspecced/getPostThreadV2.ts +0 -2
  70. package/src/lexicon/types/com/atproto/lexicon/resolveLexicon.ts +46 -0
  71. package/src/views/index.ts +3 -23
  72. package/src/views/threads-v2.ts +2 -12
  73. package/tests/utils.test.ts +45 -0
  74. package/tests/views/post-search.test.ts +221 -0
  75. package/tests/views/thread-v2.test.ts +2 -109
  76. package/tsconfig.build.tsbuildinfo +1 -1
  77. package/tsconfig.tests.tsbuildinfo +1 -1
@@ -0,0 +1,46 @@
1
+ /**
2
+ * GENERATED CODE - DO NOT MODIFY
3
+ */
4
+ import { type ValidationResult, BlobRef } from '@atproto/lexicon'
5
+ import { CID } from 'multiformats/cid'
6
+ import { validate as _validate } from '../../../../lexicons'
7
+ import {
8
+ type $Typed,
9
+ is$typed as _is$typed,
10
+ type OmitKey,
11
+ } from '../../../../util'
12
+ import type * as ComAtprotoLexiconSchema from './schema.js'
13
+
14
+ const is$typed = _is$typed,
15
+ validate = _validate
16
+ const id = 'com.atproto.lexicon.resolveLexicon'
17
+
18
+ export type QueryParams = {
19
+ /** The lexicon NSID to resolve. */
20
+ nsid: string
21
+ }
22
+ export type InputSchema = undefined
23
+
24
+ export interface OutputSchema {
25
+ /** The CID of the lexicon schema record. */
26
+ cid: string
27
+ schema: ComAtprotoLexiconSchema.Main
28
+ /** The AT-URI of the lexicon schema record. */
29
+ uri: string
30
+ }
31
+
32
+ export type HandlerInput = void
33
+
34
+ export interface HandlerSuccess {
35
+ encoding: 'application/json'
36
+ body: OutputSchema
37
+ headers?: { [key: string]: string }
38
+ }
39
+
40
+ export interface HandlerError {
41
+ status: number
42
+ message?: string
43
+ error?: 'LexiconNotFound'
44
+ }
45
+
46
+ export type HandlerOutput = HandlerError | HandlerSuccess
@@ -1246,13 +1246,11 @@ export class Views {
1246
1246
  above,
1247
1247
  below,
1248
1248
  branchingFactor,
1249
- prioritizeFollowedUsers,
1250
1249
  sort,
1251
1250
  }: {
1252
1251
  above: number
1253
1252
  below: number
1254
1253
  branchingFactor: number
1255
- prioritizeFollowedUsers: boolean
1256
1254
  sort: GetPostThreadV2QueryParams['sort']
1257
1255
  },
1258
1256
  ): { hasOtherReplies: boolean; thread: ThreadItem[] } {
@@ -1347,7 +1345,6 @@ export class Views {
1347
1345
  below,
1348
1346
  depth: 1,
1349
1347
  branchingFactor,
1350
- prioritizeFollowedUsers,
1351
1348
  },
1352
1349
  state,
1353
1350
  )
@@ -1374,7 +1371,6 @@ export class Views {
1374
1371
  opDid,
1375
1372
  branchingFactor,
1376
1373
  sort,
1377
- prioritizeFollowedUsers,
1378
1374
  viewer: state.ctx?.viewer ?? null,
1379
1375
  threadTagsBumpDown: this.threadTagsBumpDown,
1380
1376
  threadTagsHide: this.threadTagsHide,
@@ -1513,7 +1509,6 @@ export class Views {
1513
1509
  below,
1514
1510
  depth,
1515
1511
  branchingFactor,
1516
- prioritizeFollowedUsers,
1517
1512
  }: {
1518
1513
  parentUri: string
1519
1514
  isOPThread: boolean
@@ -1523,7 +1518,6 @@ export class Views {
1523
1518
  below: number
1524
1519
  depth: number
1525
1520
  branchingFactor: number
1526
- prioritizeFollowedUsers: boolean
1527
1521
  },
1528
1522
  state: HydrationState,
1529
1523
  ): { replies: ThreadTreeVisible[] | undefined; hasOtherReplies: boolean } {
@@ -1547,7 +1541,7 @@ export class Views {
1547
1541
 
1548
1542
  // Hidden.
1549
1543
  const { isOther } = this.isOtherThreadPost(
1550
- { post, postView, prioritizeFollowedUsers, rootUri, uri },
1544
+ { post, postView, rootUri, uri },
1551
1545
  state,
1552
1546
  )
1553
1547
  if (isOther) {
@@ -1570,7 +1564,6 @@ export class Views {
1570
1564
  below,
1571
1565
  depth: depth + 1,
1572
1566
  branchingFactor,
1573
- prioritizeFollowedUsers,
1574
1567
  },
1575
1568
  state,
1576
1569
  )
@@ -1699,11 +1692,9 @@ export class Views {
1699
1692
  {
1700
1693
  below,
1701
1694
  branchingFactor,
1702
- prioritizeFollowedUsers,
1703
1695
  }: {
1704
1696
  below: number
1705
1697
  branchingFactor: number
1706
- prioritizeFollowedUsers: boolean
1707
1698
  },
1708
1699
  ): ThreadOtherItem[] {
1709
1700
  const { anchor: anchorUri, uris } = skeleton
@@ -1738,7 +1729,6 @@ export class Views {
1738
1729
  childrenByParentUri,
1739
1730
  below,
1740
1731
  depth: 1,
1741
- prioritizeFollowedUsers,
1742
1732
  },
1743
1733
  state,
1744
1734
  ),
@@ -1747,7 +1737,6 @@ export class Views {
1747
1737
  return sortTrimFlattenThreadTree(anchorTree, {
1748
1738
  opDid,
1749
1739
  branchingFactor,
1750
- prioritizeFollowedUsers: false,
1751
1740
  viewer: state.ctx?.viewer ?? null,
1752
1741
  threadTagsBumpDown: this.threadTagsBumpDown,
1753
1742
  threadTagsHide: this.threadTagsHide,
@@ -1761,14 +1750,12 @@ export class Views {
1761
1750
  childrenByParentUri,
1762
1751
  below,
1763
1752
  depth,
1764
- prioritizeFollowedUsers,
1765
1753
  }: {
1766
1754
  parentUri: string
1767
1755
  rootUri: string
1768
1756
  childrenByParentUri: Record<string, string[]>
1769
1757
  below: number
1770
1758
  depth: number
1771
- prioritizeFollowedUsers: boolean
1772
1759
  },
1773
1760
  state: HydrationState,
1774
1761
  ): ThreadOtherPostNode[] | undefined {
@@ -1791,10 +1778,7 @@ export class Views {
1791
1778
 
1792
1779
  // Other posts to pull out
1793
1780
  const { isOther, hiddenByThreadgate, mutedByViewer } =
1794
- this.isOtherThreadPost(
1795
- { post, postView, rootUri, prioritizeFollowedUsers, uri },
1796
- state,
1797
- )
1781
+ this.isOtherThreadPost({ post, postView, rootUri, uri }, state)
1798
1782
  if (isOther) {
1799
1783
  // Only show hidden anchor replies, not all hidden.
1800
1784
  if (depth > 1) {
@@ -1813,7 +1797,6 @@ export class Views {
1813
1797
  childrenByParentUri,
1814
1798
  below,
1815
1799
  depth: depth + 1,
1816
- prioritizeFollowedUsers,
1817
1800
  },
1818
1801
  state,
1819
1802
  )
@@ -1932,13 +1915,11 @@ export class Views {
1932
1915
  {
1933
1916
  post,
1934
1917
  postView,
1935
- prioritizeFollowedUsers,
1936
1918
  rootUri,
1937
1919
  uri,
1938
1920
  }: {
1939
1921
  post: Post
1940
1922
  postView: PostView
1941
- prioritizeFollowedUsers: boolean
1942
1923
  rootUri: string
1943
1924
  uri: string
1944
1925
  },
@@ -1952,8 +1933,7 @@ export class Views {
1952
1933
  const opDid = creatorFromUri(rootUri)
1953
1934
  const authorDid = creatorFromUri(uri)
1954
1935
 
1955
- const showBecauseFollowing =
1956
- prioritizeFollowedUsers && !!postView.author.viewer?.following
1936
+ const showBecauseFollowing = !!postView.author.viewer?.following
1957
1937
  const hiddenByTag =
1958
1938
  authorDid !== opDid &&
1959
1939
  authorDid !== state.ctx?.viewer &&
@@ -119,7 +119,6 @@ export function sortTrimFlattenThreadTree(
119
119
  type SortTrimFlattenOptions = {
120
120
  branchingFactor: GetPostThreadV2QueryParams['branchingFactor']
121
121
  opDid: string
122
- prioritizeFollowedUsers: boolean
123
122
  sort?: GetPostThreadV2QueryParams['sort']
124
123
  viewer: HydrateCtx['viewer']
125
124
  threadTagsBumpDown: readonly string[]
@@ -182,13 +181,7 @@ function applyBumping(
182
181
  return null
183
182
  }
184
183
 
185
- const {
186
- opDid,
187
- prioritizeFollowedUsers,
188
- viewer,
189
- threadTagsBumpDown,
190
- threadTagsHide,
191
- } = opts
184
+ const { opDid, viewer, threadTagsBumpDown, threadTagsHide } = opts
192
185
 
193
186
  type BumpDirection = 'up' | 'down'
194
187
  type BumpPredicateFn = (i: ThreadMaybeOtherPostNode) => boolean
@@ -227,10 +220,7 @@ function applyBumping(
227
220
  // Followers posts.
228
221
  [
229
222
  'up',
230
- (i) =>
231
- i.type === 'post' &&
232
- prioritizeFollowedUsers &&
233
- !!i.item.value.post.author.viewer?.following,
223
+ (i) => i.type === 'post' && !!i.item.value.post.author.viewer?.following,
234
224
  ],
235
225
  // Bump-down tags.
236
226
  [
@@ -0,0 +1,45 @@
1
+ import {
2
+ PostSearchQuery,
3
+ parsePostSearchQuery,
4
+ } from '../src/data-plane/server/util'
5
+
6
+ describe('parsePostSearchQuery', () => {
7
+ type TestCase = {
8
+ input: string
9
+ output: PostSearchQuery
10
+ }
11
+
12
+ const tests: TestCase[] = [
13
+ {
14
+ input: `bluesky `,
15
+ output: { q: `bluesky`, author: undefined },
16
+ },
17
+ {
18
+ input: ` bluesky from:esb.lol`,
19
+ output: { q: `bluesky`, author: `esb.lol` },
20
+ },
21
+ {
22
+ input: `bluesky "from:esb.lol"`,
23
+ output: { q: `bluesky "from:esb.lol"`, author: undefined },
24
+ },
25
+ {
26
+ input: `bluesky mentions:@esb.lol `,
27
+ output: { q: `bluesky mentions:@esb.lol`, author: undefined },
28
+ },
29
+ {
30
+ input: `bluesky lang:"en"`,
31
+ output: { q: `bluesky lang:"en"`, author: undefined },
32
+ },
33
+ {
34
+ input: `bluesky "literal" "from:invalid" did:test:123 `,
35
+ output: {
36
+ q: `bluesky "literal" "from:invalid"`,
37
+ author: `did:test:123`,
38
+ },
39
+ },
40
+ ]
41
+
42
+ it.each(tests)(`'$input' -> '$output'`, ({ input, output }) => {
43
+ expect(parsePostSearchQuery(input)).toEqual(output)
44
+ })
45
+ })
@@ -0,0 +1,221 @@
1
+ import { AtpAgent } from '@atproto/api'
2
+ import { QueryParams as SearchPostsQueryParams } from '@atproto/api/src/client/types/app/bsky/feed/searchPosts'
3
+ import { SeedClient, TestNetwork, basicSeed } from '@atproto/dev-env'
4
+ import { DatabaseSchema } from '../../src'
5
+ import { ids } from '../../src/lexicon/lexicons'
6
+
7
+ const TAG_HIDE = 'hide'
8
+
9
+ describe('appview search', () => {
10
+ let network: TestNetwork
11
+ let agent: AtpAgent
12
+ let ozoneAgent: AtpAgent
13
+ let sc: SeedClient
14
+ let post0: Awaited<ReturnType<SeedClient['post']>>
15
+ let post1: Awaited<ReturnType<SeedClient['post']>>
16
+ let post2: Awaited<ReturnType<SeedClient['post']>>
17
+ let allResults: string[]
18
+ let nonTaggedResults: string[]
19
+
20
+ // account dids, for convenience
21
+ let alice: string
22
+ let bob: string
23
+ let carol: string
24
+
25
+ beforeAll(async () => {
26
+ network = await TestNetwork.create({
27
+ dbPostgresSchema: 'bsky_views_search',
28
+ bsky: {
29
+ searchTagsHide: new Set([TAG_HIDE]),
30
+ },
31
+ })
32
+ agent = network.bsky.getClient()
33
+ sc = network.getSeedClient()
34
+ ozoneAgent = network.ozone.getClient()
35
+ await basicSeed(sc)
36
+
37
+ alice = sc.dids.alice
38
+ bob = sc.dids.bob
39
+ carol = sc.dids.carol
40
+
41
+ post0 = await sc.post(alice, 'good doggo')
42
+ post1 = await sc.post(alice, 'bad doggo')
43
+ post2 = await sc.post(alice, 'cute doggo')
44
+ await network.processAll()
45
+
46
+ await createTag(network.bsky.db.db, {
47
+ uri: post1.ref.uriStr,
48
+ val: TAG_HIDE,
49
+ })
50
+
51
+ allResults = [post2.ref.uriStr, post1.ref.uriStr, post0.ref.uriStr]
52
+ nonTaggedResults = [post2.ref.uriStr, post0.ref.uriStr]
53
+ })
54
+
55
+ afterAll(async () => {
56
+ await deleteTags(network.bsky.db.db, {
57
+ uri: post1.ref.uriStr,
58
+ })
59
+
60
+ await network.close()
61
+ })
62
+
63
+ describe(`post search with 'top' sort`, () => {
64
+ type TestCase = {
65
+ name: string
66
+ viewer: () => string
67
+ queryParams: () => SearchPostsQueryParams
68
+ expectedPostUris: () => string[]
69
+ }
70
+
71
+ const tests: TestCase[] = [
72
+ // 'top' cases
73
+ {
74
+ name: `with 'top' sort, finds only non-tagged posts`,
75
+ viewer: () => carol,
76
+ queryParams: () => ({ q: 'doggo', sort: 'top' }),
77
+ expectedPostUris: () => nonTaggedResults,
78
+ },
79
+ {
80
+ name: `with 'top' sort, includes tagged posts from the viewer`,
81
+ viewer: () => alice,
82
+ queryParams: () => ({ q: 'doggo', sort: 'top' }),
83
+ expectedPostUris: () => allResults,
84
+ },
85
+ {
86
+ name: `with 'top' sort, finds only non-tagged posts, even specifying author`,
87
+ viewer: () => carol,
88
+ queryParams: () => ({ q: `doggo`, author: alice, sort: 'top' }),
89
+ expectedPostUris: () => nonTaggedResults,
90
+ },
91
+ {
92
+ name: `with 'top' sort, finds only non-tagged posts, even specifying from:`,
93
+ viewer: () => carol,
94
+ queryParams: () => ({
95
+ q: `doggo from:${sc.accounts[alice].handle}`,
96
+ sort: 'top',
97
+ }),
98
+ expectedPostUris: () => nonTaggedResults,
99
+ },
100
+ {
101
+ name: `with 'top' sort, finds only non-tagged posts, even specifying DID`,
102
+ viewer: () => carol,
103
+ queryParams: () => ({ q: `doggo ${alice}`, sort: 'top' }),
104
+ expectedPostUris: () => nonTaggedResults,
105
+ },
106
+ {
107
+ name: `with 'top' sort, finds no posts if specifying user who didn't post the term`,
108
+ viewer: () => carol,
109
+ queryParams: () => ({ q: `doggo ${bob}`, sort: 'top' }),
110
+ expectedPostUris: () => [],
111
+ },
112
+
113
+ // 'latest' cases
114
+ {
115
+ name: `with 'latest' sort, finds only non-tagged posts`,
116
+ viewer: () => carol,
117
+ queryParams: () => ({ q: 'doggo', sort: 'latest' }),
118
+ expectedPostUris: () => nonTaggedResults,
119
+ },
120
+ {
121
+ name: `with 'latest' sort, includes tagged posts from the viewer`,
122
+ viewer: () => alice,
123
+ queryParams: () => ({ q: 'doggo', sort: 'latest' }),
124
+ expectedPostUris: () => allResults,
125
+ },
126
+ {
127
+ name: `with 'latest' sort, finds all posts if specifying author`,
128
+ viewer: () => carol,
129
+ queryParams: () => ({
130
+ q: `doggo`,
131
+ author: alice,
132
+ sort: 'latest',
133
+ }),
134
+ expectedPostUris: () => allResults,
135
+ },
136
+ {
137
+ name: `with 'latest' sort, finds all posts if specifying from:`,
138
+ viewer: () => carol,
139
+ queryParams: () => ({
140
+ q: `doggo from:${sc.accounts[alice].handle}`,
141
+ sort: 'latest',
142
+ }),
143
+ expectedPostUris: () => allResults,
144
+ },
145
+ {
146
+ name: `with 'latest' sort, finds all posts if specifying DID`,
147
+ viewer: () => carol,
148
+ queryParams: () => ({ q: `doggo ${alice}`, sort: 'latest' }),
149
+ expectedPostUris: () => allResults,
150
+ },
151
+ {
152
+ name: `with 'latest' sort, finds no posts if specifying user who didn't post the term`,
153
+ viewer: () => carol,
154
+ queryParams: () => ({ q: `doggo ${bob}`, sort: 'latest' }),
155
+ expectedPostUris: () => [],
156
+ },
157
+ ]
158
+
159
+ it.each(tests)(
160
+ '$name',
161
+ async ({ viewer, queryParams, expectedPostUris }) => {
162
+ const res = await agent.app.bsky.feed.searchPosts(queryParams(), {
163
+ headers: await network.serviceHeaders(
164
+ viewer(),
165
+ ids.AppBskyFeedSearchPosts,
166
+ ),
167
+ })
168
+ expect(res.data.posts.map((p) => p.uri)).toStrictEqual(
169
+ expectedPostUris(),
170
+ )
171
+ },
172
+ )
173
+
174
+ it('mod service finds even tagged posts', async () => {
175
+ const resTop = await ozoneAgent.app.bsky.feed.searchPosts(
176
+ { q: 'doggo', sort: 'top' },
177
+ { headers: await network.ozone.modHeaders(ids.AppBskyFeedSearchPosts) },
178
+ )
179
+ const resLatest = await ozoneAgent.app.bsky.feed.searchPosts(
180
+ { q: 'doggo', sort: 'latest' },
181
+ { headers: await network.ozone.modHeaders(ids.AppBskyFeedSearchPosts) },
182
+ )
183
+
184
+ expect(resTop.data.posts.map((p) => p.uri)).toStrictEqual(allResults)
185
+ expect(resLatest.data.posts.map((p) => p.uri)).toStrictEqual(allResults)
186
+ })
187
+ })
188
+ })
189
+
190
+ const createTag = async (
191
+ db: DatabaseSchema,
192
+ opts: {
193
+ uri: string
194
+ val: string
195
+ },
196
+ ) => {
197
+ await db
198
+ .updateTable('record')
199
+ .set({
200
+ tags: JSON.stringify([opts.val]),
201
+ })
202
+ .where('uri', '=', opts.uri)
203
+ .returningAll()
204
+ .execute()
205
+ }
206
+
207
+ const deleteTags = async (
208
+ db: DatabaseSchema,
209
+ opts: {
210
+ uri: string
211
+ },
212
+ ) => {
213
+ await db
214
+ .updateTable('record')
215
+ .set({
216
+ tags: JSON.stringify([]),
217
+ })
218
+ .where('uri', '=', opts.uri)
219
+ .returningAll()
220
+ .execute()
221
+ }
@@ -1108,16 +1108,11 @@ describe('appview thread views v2', () => {
1108
1108
  await network.processAll()
1109
1109
  })
1110
1110
 
1111
- const threadForPostAndViewer = async (
1112
- post: string,
1113
- viewer: string,
1114
- prioritizeFollowedUsers: boolean = false,
1115
- ) => {
1111
+ const threadForPostAndViewer = async (post: string, viewer: string) => {
1116
1112
  const { data } = await agent.app.bsky.unspecced.getPostThreadV2(
1117
1113
  {
1118
1114
  anchor: post,
1119
1115
  sort: 'newest',
1120
- prioritizeFollowedUsers,
1121
1116
  },
1122
1117
  {
1123
1118
  headers: await network.serviceHeaders(
@@ -1133,13 +1128,10 @@ describe('appview thread views v2', () => {
1133
1128
  return t
1134
1129
  }
1135
1130
 
1136
- it('bumps up followed users if option is set', async () => {
1137
- const prioritizeFollowedUsers = true
1138
-
1131
+ it('bumps up followed users', async () => {
1139
1132
  const t1 = await threadForPostAndViewer(
1140
1133
  seed.root.ref.uriStr,
1141
1134
  seed.users.viewerF.did,
1142
- prioritizeFollowedUsers,
1143
1135
  )
1144
1136
  expect(t1).toEqual([
1145
1137
  expect.objectContaining({ uri: seed.root.ref.uriStr }), // root
@@ -1154,7 +1146,6 @@ describe('appview thread views v2', () => {
1154
1146
  const t2 = await threadForPostAndViewer(
1155
1147
  seed.root.ref.uriStr,
1156
1148
  seed.users.viewerNoF.did,
1157
- prioritizeFollowedUsers,
1158
1149
  )
1159
1150
  expect(t2).toEqual([
1160
1151
  expect.objectContaining({ uri: seed.root.ref.uriStr }), // root
@@ -1167,36 +1158,6 @@ describe('appview thread views v2', () => {
1167
1158
  expect.objectContaining({ uri: seed.r['0'].ref.uriStr }),
1168
1159
  ])
1169
1160
  })
1170
-
1171
- it('does not prioritize followed users if option is not set', async () => {
1172
- const t1 = await threadForPostAndViewer(
1173
- seed.root.ref.uriStr,
1174
- seed.users.viewerF.did,
1175
- )
1176
- expect(t1).toHaveLength(7)
1177
- expect(t1[0].uri).toBe(seed.root.ref.uriStr) // root
1178
- expect(t1[1].uri).toBe(seed.r['3'].ref.uriStr) // op reply
1179
- expect(t1[2].uri).toBe(seed.r['4'].ref.uriStr) // viewer reply
1180
- // newest to oldest
1181
- expect(t1[3].uri).toBe(seed.r['5'].ref.uriStr)
1182
- expect(t1[4].uri).toBe(seed.r['2'].ref.uriStr)
1183
- expect(t1[5].uri).toBe(seed.r['1'].ref.uriStr)
1184
- expect(t1[6].uri).toBe(seed.r['0'].ref.uriStr)
1185
-
1186
- const t2 = await threadForPostAndViewer(
1187
- seed.root.ref.uriStr,
1188
- seed.users.viewerNoF.did,
1189
- )
1190
- expect(t2).toHaveLength(7)
1191
- expect(t2[0].uri).toBe(seed.root.ref.uriStr) // root
1192
- expect(t2[1].uri).toBe(seed.r['3'].ref.uriStr) // op reply
1193
- expect(t2[2].uri).toBe(seed.r['5'].ref.uriStr) // viewer reply
1194
- // newest to oldest
1195
- expect(t2[3].uri).toBe(seed.r['4'].ref.uriStr)
1196
- expect(t2[4].uri).toBe(seed.r['2'].ref.uriStr)
1197
- expect(t2[5].uri).toBe(seed.r['1'].ref.uriStr)
1198
- expect(t2[6].uri).toBe(seed.r['0'].ref.uriStr)
1199
- })
1200
1161
  })
1201
1162
  })
1202
1163
  })
@@ -1960,14 +1921,11 @@ describe('appview thread views v2', () => {
1960
1921
  })
1961
1922
 
1962
1923
  describe('when prioritizing followed users', () => {
1963
- const prioritizeFollowedUsers = true
1964
-
1965
1924
  it('considers tags for bumping down and hiding', async () => {
1966
1925
  const { data } = await agent.app.bsky.unspecced.getPostThreadV2(
1967
1926
  {
1968
1927
  anchor: seed.root.ref.uriStr,
1969
1928
  sort: 'newest',
1970
- prioritizeFollowedUsers,
1971
1929
  },
1972
1930
  {
1973
1931
  headers: await network.serviceHeaders(
@@ -2003,7 +1961,6 @@ describe('appview thread views v2', () => {
2003
1961
  const { data } = await agent.app.bsky.unspecced.getPostThreadOtherV2(
2004
1962
  {
2005
1963
  anchor: seed.root.ref.uriStr,
2006
- prioritizeFollowedUsers,
2007
1964
  },
2008
1965
  {
2009
1966
  headers: await network.serviceHeaders(
@@ -2021,70 +1978,6 @@ describe('appview thread views v2', () => {
2021
1978
  ])
2022
1979
  })
2023
1980
  })
2024
-
2025
- describe('when not prioritizing followed users', () => {
2026
- const prioritizeFollowedUsers = false
2027
-
2028
- it('considers tags for bumping down and hiding', async () => {
2029
- const { data } = await agent.app.bsky.unspecced.getPostThreadV2(
2030
- {
2031
- anchor: seed.root.ref.uriStr,
2032
- sort: 'newest',
2033
- prioritizeFollowedUsers,
2034
- },
2035
- {
2036
- headers: await network.serviceHeaders(
2037
- seed.users.viewer.did,
2038
- ids.AppBskyUnspeccedGetPostThreadV2,
2039
- ),
2040
- },
2041
- )
2042
- const { thread: t, hasOtherReplies } = data
2043
-
2044
- expect(hasOtherReplies).toBe(true)
2045
- assertPosts(t)
2046
- expect(t).toEqual([
2047
- expect.objectContaining({ uri: seed.root.ref.uriStr }),
2048
- // OP (down overridden).
2049
- expect.objectContaining({ uri: seed.r['3'].ref.uriStr }),
2050
- // Viewer (hide overriden).
2051
- expect.objectContaining({ uri: seed.r['4'].ref.uriStr }),
2052
- // Following was hidden because not prioritizing.
2053
- // Not following.
2054
- expect.objectContaining({ uri: seed.r['0'].ref.uriStr }),
2055
- expect.objectContaining({ uri: seed.r['0.0'].ref.uriStr }),
2056
- expect.objectContaining({ uri: seed.r['0.1'].ref.uriStr }),
2057
- // Down.
2058
- expect.objectContaining({ uri: seed.r['1'].ref.uriStr }),
2059
- expect.objectContaining({ uri: seed.r['1.0'].ref.uriStr }),
2060
- expect.objectContaining({ uri: seed.r['1.1'].ref.uriStr }),
2061
- ])
2062
- })
2063
-
2064
- it('finds the hidden by tag', async () => {
2065
- const { data } = await agent.app.bsky.unspecced.getPostThreadOtherV2(
2066
- {
2067
- anchor: seed.root.ref.uriStr,
2068
- prioritizeFollowedUsers,
2069
- },
2070
- {
2071
- headers: await network.serviceHeaders(
2072
- seed.users.viewer.did,
2073
- ids.AppBskyUnspeccedGetPostThreadOtherV2,
2074
- ),
2075
- },
2076
- )
2077
- const { thread: t } = data
2078
-
2079
- assertHiddenPosts(t)
2080
- expect(t).toEqual([
2081
- // Following (hide).
2082
- expect.objectContaining({ uri: seed.r['5'].ref.uriStr }),
2083
- // Hide.
2084
- expect.objectContaining({ uri: seed.r['2'].ref.uriStr }),
2085
- ])
2086
- })
2087
- })
2088
1981
  })
2089
1982
  })
2090
1983