@atproto/bsky 0.0.249 → 0.0.251

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 (84) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/api/age-assurance/const.d.ts.map +1 -1
  3. package/dist/api/age-assurance/const.js +19 -0
  4. package/dist/api/age-assurance/const.js.map +1 -1
  5. package/dist/api/age-assurance/kws/age-verified.d.ts +20 -0
  6. package/dist/api/age-assurance/kws/age-verified.d.ts.map +1 -1
  7. package/dist/api/age-assurance/kws/age-verified.js +6 -0
  8. package/dist/api/age-assurance/kws/age-verified.js.map +1 -1
  9. package/dist/api/app/bsky/feed/getFeed.d.ts.map +1 -1
  10. package/dist/api/app/bsky/feed/getFeed.js +4 -0
  11. package/dist/api/app/bsky/feed/getFeed.js.map +1 -1
  12. package/dist/api/app/bsky/feed/searchPosts.js +5 -0
  13. package/dist/api/app/bsky/feed/searchPosts.js.map +1 -1
  14. package/dist/api/app/bsky/feed/searchPostsV2.js +5 -0
  15. package/dist/api/app/bsky/feed/searchPostsV2.js.map +1 -1
  16. package/dist/api/app/bsky/graph/muteActor.d.ts.map +1 -1
  17. package/dist/api/app/bsky/graph/muteActor.js +3 -0
  18. package/dist/api/app/bsky/graph/muteActor.js.map +1 -1
  19. package/dist/api/kws/types.d.ts +33 -0
  20. package/dist/api/kws/types.d.ts.map +1 -1
  21. package/dist/api/kws/types.js +3 -0
  22. package/dist/api/kws/types.js.map +1 -1
  23. package/dist/config.d.ts +2 -0
  24. package/dist/config.d.ts.map +1 -1
  25. package/dist/config.js +5 -0
  26. package/dist/config.js.map +1 -1
  27. package/dist/data-plane/index.d.ts +0 -1
  28. package/dist/data-plane/index.d.ts.map +1 -1
  29. package/dist/data-plane/index.js +0 -1
  30. package/dist/data-plane/index.js.map +1 -1
  31. package/dist/data-plane/server/bsync-subscription.d.ts +47 -0
  32. package/dist/data-plane/server/bsync-subscription.d.ts.map +1 -0
  33. package/dist/data-plane/server/bsync-subscription.js +461 -0
  34. package/dist/data-plane/server/bsync-subscription.js.map +1 -0
  35. package/dist/data-plane/server/index.d.ts +1 -0
  36. package/dist/data-plane/server/index.d.ts.map +1 -1
  37. package/dist/data-plane/server/index.js +1 -0
  38. package/dist/data-plane/server/index.js.map +1 -1
  39. package/dist/hydration/feed.d.ts +1 -2
  40. package/dist/hydration/feed.d.ts.map +1 -1
  41. package/dist/hydration/feed.js.map +1 -1
  42. package/dist/lexicons/app/bsky/ageassurance/defs.defs.d.ts +4 -0
  43. package/dist/lexicons/app/bsky/ageassurance/defs.defs.d.ts.map +1 -1
  44. package/dist/lexicons/app/bsky/ageassurance/defs.defs.js +3 -0
  45. package/dist/lexicons/app/bsky/ageassurance/defs.defs.js.map +1 -1
  46. package/dist/lexicons/chat/bsky/convo/defs.defs.js +1 -1
  47. package/dist/lexicons/chat/bsky/convo/defs.defs.js.map +1 -1
  48. package/dist/lexicons/chat/bsky/group/editGroup.defs.d.ts +4 -4
  49. package/dist/lexicons/chat/bsky/group/editGroup.defs.js +2 -2
  50. package/dist/lexicons/chat/bsky/group/editGroup.defs.js.map +1 -1
  51. package/dist/lexicons/chat/bsky/moderation/defs.defs.js +1 -1
  52. package/dist/lexicons/chat/bsky/moderation/defs.defs.js.map +1 -1
  53. package/package.json +10 -10
  54. package/src/api/age-assurance/const.ts +19 -0
  55. package/src/api/age-assurance/kws/age-verified.test.ts +98 -0
  56. package/src/api/age-assurance/kws/age-verified.ts +6 -0
  57. package/src/api/app/bsky/feed/getFeed.ts +5 -0
  58. package/src/api/app/bsky/feed/searchPosts.ts +7 -0
  59. package/src/api/app/bsky/feed/searchPostsV2.ts +7 -0
  60. package/src/api/app/bsky/graph/muteActor.ts +3 -0
  61. package/src/api/kws/types.ts +11 -0
  62. package/src/api/kws/util.test.ts +50 -0
  63. package/src/config.ts +9 -0
  64. package/src/data-plane/index.ts +0 -1
  65. package/src/data-plane/{bsync/index.ts → server/bsync-subscription.ts} +245 -121
  66. package/src/data-plane/server/index.ts +1 -0
  67. package/src/hydration/feed.ts +1 -2
  68. package/tests/__snapshots__/feed-generation.test.ts.snap +62 -15
  69. package/tests/data-plane/thread-mutes.test.ts +2 -0
  70. package/tests/feed-generation.test.ts +55 -9
  71. package/tests/stash.test.ts +6 -1
  72. package/tests/views/age-assurance-v2.test.ts +3 -0
  73. package/tests/views/age-assurance.test.ts +8 -0
  74. package/tests/views/bookmarks.test.ts +19 -0
  75. package/tests/views/drafts.test.ts +25 -2
  76. package/tests/views/mute-lists.test.ts +2 -0
  77. package/tests/views/mutes.test.ts +1 -0
  78. package/tests/views/notifications.test.ts +16 -0
  79. package/tests/views/post-search.test.ts +81 -0
  80. package/tsconfig.build.tsbuildinfo +1 -1
  81. package/dist/data-plane/bsync/index.d.ts +0 -11
  82. package/dist/data-plane/bsync/index.d.ts.map +0 -1
  83. package/dist/data-plane/bsync/index.js +0 -376
  84. package/dist/data-plane/bsync/index.js.map +0 -1
@@ -1036,6 +1036,9 @@ describe('notification views', () => {
1036
1036
 
1037
1037
  describe('preferences v2', () => {
1038
1038
  beforeEach(async () => {
1039
+ // Drain pending bsync ops before clearing, so a stale op can't land
1040
+ // after the reset.
1041
+ await network.processAll()
1039
1042
  await clearPrivateData(db)
1040
1043
  })
1041
1044
 
@@ -1354,6 +1357,9 @@ describe('notification views', () => {
1354
1357
  })
1355
1358
 
1356
1359
  beforeEach(async () => {
1360
+ // Drain pending bsync ops before clearing, so a stale op can't land
1361
+ // after the reset.
1362
+ await network.processAll()
1357
1363
  await clearActivitySubscription(db)
1358
1364
  })
1359
1365
 
@@ -1383,6 +1389,7 @@ describe('notification views', () => {
1383
1389
  subject: subjectDid,
1384
1390
  activitySubscription: val,
1385
1391
  })
1392
+ await network.processAll()
1386
1393
 
1387
1394
  const { data: listData } = await list(actorDid)
1388
1395
  expect(listData).toEqual({
@@ -1413,6 +1420,7 @@ describe('notification views', () => {
1413
1420
  subject: subjectDid,
1414
1421
  activitySubscription: valUpdate,
1415
1422
  })
1423
+ await network.processAll()
1416
1424
 
1417
1425
  const { data: listData } = await list(actorDid)
1418
1426
  expect(listData).toEqual({
@@ -1435,10 +1443,12 @@ describe('notification views', () => {
1435
1443
  const valDelete = { post: false, reply: false }
1436
1444
 
1437
1445
  await put(actorDid, subjectDid, valCreate)
1446
+ await network.processAll()
1438
1447
  const { data: list0 } = await list(actorDid)
1439
1448
  expect(list0.subscriptions).toHaveLength(1)
1440
1449
 
1441
1450
  await put(actorDid, subjectDid, valDelete)
1451
+ await network.processAll()
1442
1452
  const { data: list1 } = await list(actorDid)
1443
1453
  expect(list1.subscriptions).toHaveLength(0)
1444
1454
  })
@@ -1454,6 +1464,7 @@ describe('notification views', () => {
1454
1464
  await put(actorDid, eve, val)
1455
1465
  await put(actorDid, fred, val)
1456
1466
  await put(actorDid, blocked, val) // blocked is removed from the list.
1467
+ await network.processAll()
1457
1468
 
1458
1469
  const results = (
1459
1470
  results: AppBskyNotificationListActivitySubscriptions.OutputSchema[],
@@ -1507,24 +1518,29 @@ describe('notification views', () => {
1507
1518
 
1508
1519
  // 'none' declaration.
1509
1520
  await put(viewer, bob, val)
1521
+ await network.processAll()
1510
1522
  await expect(viewerActivitySub(viewer, bob)).resolves.toBeUndefined()
1511
1523
 
1512
1524
  // 'mutuals' declaration and both follow.
1513
1525
  await put(viewer, carol, val)
1526
+ await network.processAll()
1514
1527
  await expect(viewerActivitySub(viewer, carol)).resolves.toStrictEqual(
1515
1528
  val,
1516
1529
  )
1517
1530
 
1518
1531
  // 'mutuals' declaration but only actor follows.
1519
1532
  await put(viewer, dan, val)
1533
+ await network.processAll()
1520
1534
  await expect(viewerActivitySub(viewer, dan)).resolves.toBeUndefined()
1521
1535
 
1522
1536
  // 'mutuals' declaration but only subject follows.
1523
1537
  await put(viewer, eve, val)
1538
+ await network.processAll()
1524
1539
  await expect(viewerActivitySub(viewer, eve)).resolves.toBeUndefined()
1525
1540
 
1526
1541
  // 'followers' declaration and viewer follows.
1527
1542
  await put(viewer, fred, val)
1543
+ await network.processAll()
1528
1544
  await expect(viewerActivitySub(viewer, carol)).resolves.toStrictEqual(
1529
1545
  val,
1530
1546
  )
@@ -5,6 +5,7 @@ import type { DidString } from '@atproto/syntax'
5
5
  import { DatabaseSchema } from '../../src/index.js'
6
6
 
7
7
  const TAG_HIDE = 'hide'
8
+ const TAG_ALWAYS_HIDE = 'always-hide'
8
9
 
9
10
  describe('appview search', () => {
10
11
  let network: TestNetwork
@@ -14,6 +15,10 @@ describe('appview search', () => {
14
15
  let post0: Awaited<ReturnType<SeedClient['post']>>
15
16
  let post1: Awaited<ReturnType<SeedClient['post']>>
16
17
  let post2: Awaited<ReturnType<SeedClient['post']>>
18
+ // 'unicorn' term, kept separate from the 'doggo' posts above so the
19
+ // always-hide cases don't perturb the existing expectations.
20
+ let unicornPost: Awaited<ReturnType<SeedClient['post']>>
21
+ let unicornPostAlwaysHidden: Awaited<ReturnType<SeedClient['post']>>
17
22
  let allResults: string[]
18
23
  let nonTaggedResults: string[]
19
24
 
@@ -27,6 +32,7 @@ describe('appview search', () => {
27
32
  dbPostgresSchema: 'bsky_views_search',
28
33
  bsky: {
29
34
  searchTagsHide: new Set([TAG_HIDE]),
35
+ searchTagsHideAll: new Set([TAG_ALWAYS_HIDE]),
30
36
  },
31
37
  })
32
38
  agent = network.bsky.getAgent()
@@ -43,10 +49,18 @@ describe('appview search', () => {
43
49
  post2 = await sc.post(alice, 'cute doggo')
44
50
  await network.processAll()
45
51
 
52
+ unicornPost = await sc.post(alice, 'a unicorn')
53
+ unicornPostAlwaysHidden = await sc.post(alice, 'another unicorn')
54
+ await network.processAll()
55
+
46
56
  await createTag(network.bsky.db.db, {
47
57
  uri: post1.ref.uriStr,
48
58
  val: TAG_HIDE,
49
59
  })
60
+ await createTag(network.bsky.db.db, {
61
+ uri: unicornPostAlwaysHidden.ref.uriStr,
62
+ val: TAG_ALWAYS_HIDE,
63
+ })
50
64
 
51
65
  allResults = [post2.ref.uriStr, post1.ref.uriStr, post0.ref.uriStr]
52
66
  nonTaggedResults = [post2.ref.uriStr, post0.ref.uriStr]
@@ -180,6 +194,73 @@ describe('appview search', () => {
180
194
  expect(resLatest.data.posts.map((p) => p.uri)).toStrictEqual(allResults)
181
195
  })
182
196
  })
197
+
198
+ describe('searchTagsHideAll', () => {
199
+ // Unlike searchTagsHide, an always-hide tag is filtered from every
200
+ // surface: both 'top' and 'latest', and even when an author is specified.
201
+ it.each(['top', 'latest'] as const)(
202
+ `with '%s' sort, hides always-hidden posts`,
203
+ async (sort) => {
204
+ const res = await agent.app.bsky.feed.searchPosts(
205
+ { q: 'unicorn', sort },
206
+ {
207
+ headers: await network.serviceHeaders(
208
+ carol,
209
+ ids.AppBskyFeedSearchPosts,
210
+ ),
211
+ },
212
+ )
213
+ expect(res.data.posts.map((p) => p.uri)).toStrictEqual([
214
+ unicornPost.ref.uriStr,
215
+ ])
216
+ },
217
+ )
218
+
219
+ it.each(['top', 'latest'] as const)(
220
+ `with '%s' sort, hides always-hidden posts even when specifying author`,
221
+ async (sort) => {
222
+ const res = await agent.app.bsky.feed.searchPosts(
223
+ { q: 'unicorn', author: alice, sort },
224
+ {
225
+ headers: await network.serviceHeaders(
226
+ carol,
227
+ ids.AppBskyFeedSearchPosts,
228
+ ),
229
+ },
230
+ )
231
+ expect(res.data.posts.map((p) => p.uri)).toStrictEqual([
232
+ unicornPost.ref.uriStr,
233
+ ])
234
+ },
235
+ )
236
+
237
+ it('includes always-hidden posts from the viewer', async () => {
238
+ const res = await agent.app.bsky.feed.searchPosts(
239
+ { q: 'unicorn', sort: 'latest' },
240
+ {
241
+ headers: await network.serviceHeaders(
242
+ alice,
243
+ ids.AppBskyFeedSearchPosts,
244
+ ),
245
+ },
246
+ )
247
+ expect(res.data.posts.map((p) => p.uri)).toStrictEqual([
248
+ unicornPostAlwaysHidden.ref.uriStr,
249
+ unicornPost.ref.uriStr,
250
+ ])
251
+ })
252
+
253
+ it('mod service finds even always-hidden posts', async () => {
254
+ const res = await ozoneAgent.app.bsky.feed.searchPosts(
255
+ { q: 'unicorn', sort: 'latest' },
256
+ { headers: await network.ozone.modHeaders(ids.AppBskyFeedSearchPosts) },
257
+ )
258
+ expect(res.data.posts.map((p) => p.uri)).toStrictEqual([
259
+ unicornPostAlwaysHidden.ref.uriStr,
260
+ unicornPost.ref.uriStr,
261
+ ])
262
+ })
263
+ })
183
264
  })
184
265
 
185
266
  const createTag = async (