@atproto/bsky 0.0.157 → 0.0.159

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 (32) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/data-plane/server/db/db.d.ts +1 -0
  3. package/dist/data-plane/server/db/db.d.ts.map +1 -1
  4. package/dist/data-plane/server/db/db.js.map +1 -1
  5. package/dist/data-plane/server/db/index.d.ts +1 -0
  6. package/dist/data-plane/server/db/index.d.ts.map +1 -1
  7. package/dist/data-plane/server/db/tables/record.d.ts +2 -1
  8. package/dist/data-plane/server/db/tables/record.d.ts.map +1 -1
  9. package/dist/data-plane/server/db/tables/record.js.map +1 -1
  10. package/dist/data-plane/server/index.d.ts +2 -1
  11. package/dist/data-plane/server/index.d.ts.map +1 -1
  12. package/dist/data-plane/server/index.js.map +1 -1
  13. package/dist/data-plane/server/routes/private-data.d.ts +1 -1
  14. package/dist/data-plane/server/routes/private-data.d.ts.map +1 -1
  15. package/dist/data-plane/server/routes/private-data.js +3 -2
  16. package/dist/data-plane/server/routes/private-data.js.map +1 -1
  17. package/dist/proto/bsky_pb.d.ts +17 -13
  18. package/dist/proto/bsky_pb.d.ts.map +1 -1
  19. package/dist/proto/bsky_pb.js +36 -26
  20. package/dist/proto/bsky_pb.js.map +1 -1
  21. package/package.json +7 -7
  22. package/proto/bsky.proto +14 -13
  23. package/src/data-plane/server/db/db.ts +2 -0
  24. package/src/data-plane/server/db/index.ts +1 -0
  25. package/src/data-plane/server/db/tables/record.ts +3 -1
  26. package/src/data-plane/server/index.ts +3 -1
  27. package/src/data-plane/server/routes/private-data.ts +6 -2
  28. package/src/proto/bsky_pb.ts +32 -26
  29. package/tests/views/thread-v2.test.ts +31 -33
  30. package/tsconfig.tests.tsbuildinfo +1 -1
  31. package/tests/seed/thread-v2.ts +0 -874
  32. package/tests/seed/util.ts +0 -52
@@ -1,874 +0,0 @@
1
- import { sql } from 'kysely'
2
- import { AppBskyFeedPost } from '@atproto/api'
3
- import {
4
- RecordRef,
5
- SeedClient,
6
- TestNetwork,
7
- TestNetworkNoAppView,
8
- } from '@atproto/dev-env'
9
- import { DatabaseSchema } from '../../src/data-plane/server/db/database-schema'
10
- import { User, createUsers } from './util'
11
-
12
- type ReplyFn = (
13
- replyAuthor: User,
14
- overridesOrCb?: Partial<AppBskyFeedPost.Record> | ReplyCb,
15
- maybeReplyCb?: ReplyCb,
16
- ) => Promise<void>
17
-
18
- type ReplyCb = (r: ReplyFn) => Promise<void>
19
-
20
- export const TAG_BUMP_DOWN = 'down'
21
- export const TAG_HIDE = 'hide'
22
-
23
- const rootReplyFnBuilder = <T extends TestNetworkNoAppView>(
24
- sc: SeedClient<T>,
25
- root: RecordRef,
26
- parent: RecordRef,
27
- prevBreadcrumbs: string,
28
- posts: Record<
29
- string,
30
- | Awaited<ReturnType<SeedClient['post']>>
31
- | Awaited<ReturnType<SeedClient['reply']>>
32
- >,
33
- ): ReplyFn => {
34
- let index = 0
35
- return async (
36
- replyAuthor: User,
37
- overridesOrCb?: Partial<AppBskyFeedPost.Record> | ReplyCb,
38
- maybeReplyCb?: ReplyCb,
39
- ) => {
40
- let overrides: Partial<AppBskyFeedPost.Record> | undefined
41
- let replyCb: ReplyCb | undefined
42
- if (overridesOrCb && typeof overridesOrCb === 'function') {
43
- replyCb = overridesOrCb
44
- } else {
45
- overrides = overridesOrCb
46
- replyCb = maybeReplyCb
47
- }
48
-
49
- const breadcrumbs = prevBreadcrumbs
50
- ? `${prevBreadcrumbs}.${index++}`
51
- : `${index++}`
52
- const text = breadcrumbs
53
- const reply = await sc.reply(
54
- replyAuthor.did,
55
- root,
56
- parent,
57
- text,
58
- undefined,
59
- undefined,
60
- overrides,
61
- )
62
- posts[breadcrumbs] = reply
63
- // Await for this post to be processed before replying to it.
64
- replyCb && (await sc.network.processAll())
65
- await replyCb?.(rootReplyFnBuilder(sc, root, reply.ref, breadcrumbs, posts))
66
- }
67
- }
68
-
69
- const createThread = async <T extends TestNetworkNoAppView>(
70
- sc: SeedClient<T>,
71
- rootAuthor: User,
72
- overridesOrCb?: Partial<AppBskyFeedPost.Record> | ReplyCb,
73
- maybeReplyCb?: ReplyCb,
74
- ) => {
75
- let overrides: Partial<AppBskyFeedPost.Record> | undefined
76
- let replyCb: ReplyCb | undefined
77
- if (overridesOrCb && typeof overridesOrCb === 'function') {
78
- replyCb = overridesOrCb
79
- } else {
80
- overrides = overridesOrCb
81
- replyCb = maybeReplyCb
82
- }
83
-
84
- const replies: Record<string, Awaited<ReturnType<SeedClient['reply']>>> = {}
85
- const breadcrumbs = ''
86
- const text = 'root'
87
- const root = await sc.post(
88
- rootAuthor.did,
89
- text,
90
- undefined,
91
- undefined,
92
- undefined,
93
- overrides,
94
- )
95
- // Await for this post to be processed before replying to it.
96
- replyCb && (await sc.network.processAll())
97
- await replyCb?.(
98
- rootReplyFnBuilder(sc, root.ref, root.ref, breadcrumbs, replies),
99
- )
100
- return { root, replies }
101
- }
102
-
103
- export async function simple(sc: SeedClient<TestNetwork>, prefix = 'simple') {
104
- const users = await createUsers(sc, prefix, [
105
- 'op',
106
- 'alice',
107
- 'bob',
108
- 'carol',
109
- ] as const)
110
- const { op, alice, bob, carol } = users
111
-
112
- const { root, replies: r } = await createThread(sc, op, async (r) => {
113
- await r(op, async (r) => {
114
- await r(op)
115
- })
116
- await r(alice)
117
- await r(bob, async (r) => {
118
- await r(alice)
119
- })
120
- await r(carol)
121
- })
122
-
123
- return {
124
- seedClient: sc,
125
- users,
126
- root,
127
- r,
128
- }
129
- }
130
-
131
- export async function long(sc: SeedClient<TestNetwork>) {
132
- const users = await createUsers(sc, 'long', [
133
- 'op',
134
- 'alice',
135
- 'bob',
136
- 'carol',
137
- 'dan',
138
- ] as const)
139
- const { op, alice, bob, carol, dan } = users
140
-
141
- const { root, replies: r } = await createThread(sc, op, async (r) => {
142
- await r(op, async (r) => {
143
- await r(op, async (r) => {
144
- await r(op, async (r) => {
145
- await r(op, async (r) => {
146
- await r(op)
147
- })
148
- })
149
- await r(op)
150
- })
151
- })
152
-
153
- await r(alice)
154
- await r(bob)
155
- await r(carol)
156
-
157
- await r(op, async (r) => {
158
- await r(op, async (r) => {
159
- await r(alice, async (r) => {
160
- await r(op, async (r) => {
161
- await r(op)
162
- })
163
- })
164
- })
165
- })
166
-
167
- await r(alice)
168
- await r(bob)
169
- await r(carol)
170
- })
171
-
172
- await sc.like(op.did, r['5'].ref)
173
- await sc.like(bob.did, r['5'].ref)
174
- await sc.like(carol.did, r['5'].ref)
175
- await sc.like(dan.did, r['5'].ref)
176
-
177
- await sc.like(op.did, r['6'].ref)
178
- await sc.like(alice.did, r['6'].ref)
179
- await sc.like(carol.did, r['6'].ref)
180
-
181
- await sc.like(op.did, r['7'].ref)
182
- await sc.like(bob.did, r['7'].ref)
183
-
184
- return {
185
- seedClient: sc,
186
- users,
187
- root,
188
- r,
189
- }
190
- }
191
-
192
- export async function deep(sc: SeedClient<TestNetwork>) {
193
- const users = await createUsers(sc, 'deep', ['op'] as const)
194
- const { op } = users
195
-
196
- let counter = 0
197
- const { root, replies: r } = await createThread(sc, op, async (r) => {
198
- const recursiveReply = async (rFn: ReplyFn) => {
199
- if (counter < 18) {
200
- counter++
201
- await rFn(op, async (r) => recursiveReply(r))
202
- }
203
- }
204
- await recursiveReply(r)
205
- })
206
-
207
- return {
208
- seedClient: sc,
209
- users,
210
- root,
211
- r,
212
- }
213
- }
214
-
215
- export async function branchingFactor(sc: SeedClient<TestNetwork>) {
216
- const users = await createUsers(sc, 'bf', ['op', 'bob'] as const)
217
- const { op, bob } = users
218
-
219
- const { root, replies: r } = await createThread(sc, op, async (r) => {
220
- await r(bob, async (r) => {
221
- await r(bob, async (r) => {
222
- await r(bob)
223
- await r(bob)
224
- await r(bob)
225
- await r(bob)
226
- })
227
- await r(bob, async (r) => {
228
- await r(bob)
229
- await r(bob)
230
- await r(bob)
231
- await r(bob)
232
- })
233
- await r(bob, async (r) => {
234
- await r(bob)
235
- await r(bob)
236
- await r(bob)
237
- await r(bob)
238
- })
239
- await r(bob, async (r) => {
240
- await r(bob)
241
- await r(bob)
242
- await r(bob)
243
- await r(bob)
244
- })
245
- })
246
- await r(bob, async (r) => {
247
- await r(bob, async (r) => {
248
- // This is the only case in this seed where a reply has 1 reply instead of 4,
249
- // to have cases of different lengths in the same tree.
250
- await r(bob)
251
- })
252
- await r(bob, async (r) => {
253
- await r(bob)
254
- await r(bob)
255
- await r(bob)
256
- await r(bob)
257
- })
258
- await r(bob, async (r) => {
259
- await r(bob)
260
- await r(bob)
261
- await r(bob)
262
- await r(bob)
263
- })
264
- await r(bob, async (r) => {
265
- await r(bob)
266
- await r(bob)
267
- await r(bob)
268
- await r(bob)
269
- })
270
- })
271
- await r(bob, async (r) => {
272
- await r(bob, async (r) => {
273
- await r(bob)
274
- await r(bob)
275
- await r(bob)
276
- await r(bob)
277
- })
278
- await r(bob, async (r) => {
279
- await r(bob)
280
- await r(bob)
281
- await r(bob)
282
- await r(bob)
283
- })
284
- await r(bob, async (r) => {
285
- await r(bob)
286
- await r(bob)
287
- await r(bob)
288
- await r(bob)
289
- })
290
- await r(bob, async (r) => {
291
- await r(bob)
292
- await r(bob)
293
- await r(bob)
294
- await r(bob)
295
- })
296
- })
297
- await r(bob, async (r) => {
298
- await r(bob, async (r) => {
299
- await r(bob)
300
- await r(bob)
301
- await r(bob)
302
- await r(bob)
303
- // This is the only case in this seed where a reply has 5 replies instead of 4,
304
- // to have cases of different lengths in the same tree.
305
- await r(bob)
306
- })
307
- await r(bob, async (r) => {
308
- await r(bob)
309
- await r(bob)
310
- await r(bob)
311
- await r(bob)
312
- })
313
- await r(bob, async (r) => {
314
- await r(bob)
315
- await r(bob)
316
- await r(bob)
317
- await r(bob)
318
- })
319
- await r(bob, async (r) => {
320
- await r(bob)
321
- await r(bob)
322
- await r(bob)
323
- await r(bob)
324
- })
325
- })
326
- })
327
-
328
- return {
329
- seedClient: sc,
330
- users,
331
- root,
332
- r,
333
- }
334
- }
335
-
336
- export async function annotateMoreReplies(sc: SeedClient<TestNetwork>) {
337
- const users = await createUsers(sc, 'mr', ['op', 'alice'] as const)
338
- const { op, alice } = users
339
-
340
- const { root, replies: r } = await createThread(sc, op, async (r) => {
341
- await r(alice, async (r) => {
342
- await r(alice, async (r) => {
343
- await r(alice, async (r) => {
344
- await r(alice, async (r) => {
345
- // more replies... (below = 4)
346
- await r(alice, async (r) => {
347
- await r(alice)
348
- })
349
- await r(alice)
350
- await r(alice, async (r) => {
351
- await r(alice, async (r) => {
352
- await r(alice)
353
- })
354
- })
355
- await r(alice)
356
- await r(alice)
357
- })
358
- })
359
- })
360
- await r(alice, async (r) => {
361
- await r(alice, async (r) => {
362
- await r(alice)
363
- })
364
- })
365
- })
366
- await r(alice, async (r) => {
367
- await r(alice, async (r) => {
368
- await r(alice)
369
- await r(alice)
370
- // more replies... (branchingFactor = 2)
371
- await r(alice)
372
- await r(alice)
373
- await r(alice)
374
- })
375
- await r(alice, async (r) => {
376
- await r(alice)
377
- await r(alice)
378
- })
379
- // more replies... (branchingFactor = 2)
380
- await r(alice)
381
- })
382
- await r(alice) // anchor reply not limited by branchingFactor
383
- })
384
-
385
- return {
386
- seedClient: sc,
387
- users,
388
- root,
389
- r,
390
- }
391
- }
392
-
393
- export async function annotateOP(sc: SeedClient<TestNetwork>) {
394
- const users = await createUsers(sc, 'op', ['op', 'alice', 'bob'] as const)
395
- const { op, alice, bob } = users
396
-
397
- const { root, replies: r } = await createThread(sc, op, async (r) => {
398
- await r(op, async (r) => {
399
- await r(op, async (r) => {
400
- await r(op)
401
- })
402
- })
403
- await r(alice, async (r) => {
404
- await r(alice)
405
- })
406
- await r(op, async (r) => {
407
- await r(bob, async (r) => {
408
- await r(op)
409
- })
410
- })
411
- })
412
-
413
- return {
414
- seedClient: sc,
415
- users,
416
- root,
417
- r,
418
- }
419
- }
420
-
421
- export async function sort(sc: SeedClient<TestNetwork>) {
422
- const users = await createUsers(sc, 'sort', [
423
- 'op',
424
- 'alice',
425
- 'bob',
426
- 'carol',
427
- ] as const)
428
- const { op, alice, bob, carol } = users
429
-
430
- const { root, replies: r } = await createThread(sc, op, async (r) => {
431
- // 0 likes
432
- await r(alice, async (r) => {
433
- await r(carol) // 0 likes
434
- await r(alice) // 2 likes
435
- await r(bob) // 1 like
436
- })
437
- // 3 likes
438
- await r(carol, async (r) => {
439
- await r(bob) // 1 like
440
- await r(carol) // 2 likes
441
- await r(alice) // 0 likes
442
- })
443
- // 2 likes
444
- await r(bob, async (r) => {
445
- await r(bob) // 2 likes
446
- await r(alice) // 1 like
447
- await r(carol) // 0 likes
448
- })
449
- })
450
-
451
- // likes depth 1
452
- await sc.like(alice.did, r['2'].ref)
453
- await sc.like(carol.did, r['2'].ref)
454
- await sc.like(op.did, r['1'].ref) // op like
455
- await sc.like(bob.did, r['1'].ref)
456
- await sc.like(carol.did, r['1'].ref)
457
-
458
- // likes depth 2
459
- await sc.like(bob.did, r['0.1'].ref)
460
- await sc.like(carol.did, r['0.1'].ref)
461
- await sc.like(op.did, r['0.2'].ref) // op like
462
- await sc.like(bob.did, r['1.1'].ref)
463
- await sc.like(carol.did, r['1.1'].ref)
464
- await sc.like(bob.did, r['1.0'].ref)
465
- await sc.like(bob.did, r['2.0'].ref)
466
- await sc.like(carol.did, r['2.0'].ref)
467
- await sc.like(bob.did, r['2.1'].ref)
468
-
469
- return {
470
- seedClient: sc,
471
- users,
472
- root,
473
- r,
474
- }
475
- }
476
-
477
- export async function bumpOpAndViewer(sc: SeedClient<TestNetwork>) {
478
- const users = await createUsers(sc, 'bumpOV', [
479
- 'op',
480
- 'viewer',
481
- 'alice',
482
- 'bob',
483
- 'carol',
484
- ] as const)
485
- const { op, viewer, alice, bob, carol } = users
486
-
487
- const { root, replies: r } = await createThread(sc, op, async (r) => {
488
- // 1 like
489
- await r(alice, async (r) => {
490
- await r(carol) // 0 likes
491
- await r(alice) // 2 likes
492
- await r(bob) // 1 like
493
- await r(viewer) // 0 likes
494
- await r(op) // 0 likes
495
- })
496
- // 3 likes
497
- await r(carol, async (r) => {
498
- await r(bob) // 1 like
499
- await r(carol) // 2 likes
500
- await r(op) // 0 likes
501
- await r(viewer) // 1 like
502
- await r(alice) // 0 likes
503
- })
504
- // 2 likes
505
- await r(bob, async (r) => {
506
- await r(viewer) // 0 likes
507
- await r(bob) // 4 likes
508
- await r(op) // 0 likes
509
- await r(alice) // 1 like
510
- await r(carol) // 1 like
511
- })
512
- // 0 likes
513
- await r(op, async (r) => {
514
- await r(viewer) // 0 likes
515
- await r(bob) // 0 likes
516
- await r(op) // 0 likes
517
- await r(alice) // 0 likes
518
- await r(carol) // 0 likes
519
- })
520
- // 0 likes
521
- await r(viewer, async (r) => {
522
- await r(bob) // 1 like
523
- await r(carol) // 1 like
524
- await r(op) // 0 likes
525
- await r(viewer) // 0 likes
526
- await r(alice) // 0 likes
527
- })
528
- })
529
-
530
- // likes depth 1
531
- await sc.like(alice.did, r['2'].ref)
532
- await sc.like(carol.did, r['2'].ref)
533
- await sc.like(viewer.did, r['0'].ref)
534
- await sc.like(op.did, r['1'].ref) // op like
535
- await sc.like(bob.did, r['1'].ref)
536
- await sc.like(carol.did, r['1'].ref)
537
-
538
- // likes depth 2
539
- await sc.like(bob.did, r['0.1'].ref)
540
- await sc.like(carol.did, r['0.1'].ref)
541
- await sc.like(op.did, r['0.2'].ref) // op like
542
- await sc.like(bob.did, r['1.1'].ref)
543
- await sc.like(carol.did, r['1.1'].ref)
544
- await sc.like(bob.did, r['1.0'].ref)
545
- await sc.like(alice.did, r['2.1'].ref)
546
- await sc.like(bob.did, r['2.1'].ref)
547
- await sc.like(carol.did, r['2.1'].ref)
548
- await sc.like(viewer.did, r['2.1'].ref)
549
- await sc.like(bob.did, r['1.3'].ref)
550
- await sc.like(bob.did, r['2.3'].ref)
551
- await sc.like(viewer.did, r['2.4'].ref)
552
- await sc.like(viewer.did, r['4.0'].ref)
553
- await sc.like(alice.did, r['4.1'].ref)
554
-
555
- return {
556
- seedClient: sc,
557
- users,
558
- root,
559
- r,
560
- }
561
- }
562
-
563
- export async function bumpGroupSorting(sc: SeedClient<TestNetwork>) {
564
- const users = await createUsers(sc, 'bumpGS', [
565
- 'op',
566
- 'viewer',
567
- 'alice',
568
- ] as const)
569
- const { op, viewer, alice } = users
570
-
571
- const { root, replies: r } = await createThread(sc, op, async (r) => {
572
- await r(viewer)
573
- await r(op)
574
- await r(alice)
575
- await r(op)
576
- await r(viewer)
577
- await r(op)
578
- await r(alice)
579
- await r(viewer)
580
- })
581
-
582
- return {
583
- seedClient: sc,
584
- users,
585
- root,
586
- r,
587
- }
588
- }
589
-
590
- export async function bumpFollows(sc: SeedClient<TestNetwork>) {
591
- const users = await createUsers(sc, 'bumpF', [
592
- 'op',
593
- 'viewerF',
594
- 'viewerNoF',
595
- 'alice',
596
- 'bob',
597
- 'carol',
598
- ] as const)
599
-
600
- const { op, viewerF, viewerNoF, alice, bob, carol } = users
601
-
602
- const { root, replies: r } = await createThread(sc, op, async (r) => {
603
- await r(alice)
604
- await r(bob)
605
- await r(carol)
606
- await r(op)
607
- await r(viewerF)
608
- await r(viewerNoF)
609
- })
610
-
611
- await sc.follow(viewerF.did, alice.did)
612
- await sc.follow(viewerF.did, bob.did)
613
- // Does not follow carol.
614
-
615
- return {
616
- seedClient: sc,
617
- users,
618
- root,
619
- r,
620
- }
621
- }
622
-
623
- export async function blockDeletionAuth(
624
- sc: SeedClient<TestNetwork>,
625
- labelerDid: string,
626
- ) {
627
- const users = await createUsers(sc, 'bda', [
628
- 'op',
629
- 'opBlocked',
630
- 'alice',
631
- 'auth',
632
- 'blocker',
633
- 'blocked',
634
- ] as const)
635
-
636
- const { op, opBlocked, alice, auth, blocker, blocked } = users
637
-
638
- const { root, replies: r } = await createThread(sc, op, async (r) => {
639
- // 1p block, hidden for `blocked`.
640
- await r(blocker, async (r) => {
641
- await r(alice)
642
- })
643
-
644
- // 3p block, hidden for all.
645
- await r(opBlocked, async (r) => {
646
- await r(op)
647
- await r(alice)
648
- })
649
-
650
- // Deleted, hidden for all.
651
- await r(alice, async (r) => {
652
- await r(alice)
653
- })
654
-
655
- // User configured to only be seend by authenticated users.
656
- // Requires the test sets a `!no-unauthenticated` label for this user.
657
- await r(auth, async (r) => {
658
- // Another auth-only to show that the parent chain is preserved in the thread.
659
- await r(auth, async (r) => {
660
- await r(alice)
661
- })
662
- })
663
- })
664
-
665
- await sc.deletePost(alice.did, r['2'].ref.uri)
666
- await sc.block(blocker.did, blocked.did)
667
- await sc.block(op.did, opBlocked.did)
668
-
669
- const db = sc.network.bsky.db.db
670
- await createLabel(db, {
671
- src: labelerDid,
672
- uri: auth.did,
673
- cid: '',
674
- val: '!no-unauthenticated',
675
- })
676
-
677
- return {
678
- seedClient: sc,
679
- users,
680
- root,
681
- r,
682
- }
683
- }
684
-
685
- export async function mutes(sc: SeedClient<TestNetwork>) {
686
- const users = await createUsers(sc, 'mutes', [
687
- 'op',
688
- 'opMuted',
689
- 'alice',
690
- 'muted',
691
- 'muter',
692
- ] as const)
693
-
694
- const { op, opMuted, alice, muted, muter } = users
695
-
696
- const { root, replies: r } = await createThread(sc, op, async (r) => {
697
- await r(opMuted, async (r) => {
698
- await r(alice)
699
- await r(muted)
700
- })
701
-
702
- await r(muted, async (r) => {
703
- await r(opMuted)
704
- await r(alice)
705
- })
706
- })
707
-
708
- await sc.mute(op.did, opMuted.did)
709
- await sc.mute(muter.did, muted.did)
710
-
711
- return {
712
- seedClient: sc,
713
- users,
714
- root,
715
- r,
716
- }
717
- }
718
-
719
- export async function threadgated(sc: SeedClient<TestNetwork>) {
720
- const users = await createUsers(sc, 'tg', [
721
- 'op',
722
- 'opMuted',
723
- 'viewer',
724
- 'alice',
725
- 'bob',
726
- ] as const)
727
-
728
- const { op, opMuted, alice, bob } = users
729
-
730
- const { root, replies: r } = await createThread(sc, op, async (r) => {
731
- // Muted moves down below threadgated.
732
- await r(opMuted)
733
-
734
- // Threadgated moves down.
735
- await r(alice, async (r) => {
736
- await r(alice)
737
- await r(bob)
738
- await r(op) // OP moves up.
739
- })
740
-
741
- await r(bob, async (r) => {
742
- await r(alice)
743
- await r(bob) // Threadgated is omitted if fetched from the root.
744
- await r(op) // OP moves down.
745
- })
746
- })
747
-
748
- await sc.agent.app.bsky.feed.threadgate.create(
749
- {
750
- repo: op.did,
751
- rkey: root.ref.uri.rkey,
752
- },
753
- {
754
- post: root.ref.uriStr,
755
- createdAt: new Date().toISOString(),
756
- hiddenReplies: [r['1'].ref.uriStr, r['2.1'].ref.uriStr],
757
- },
758
- sc.getHeaders(op.did),
759
- )
760
-
761
- // Just throw a mute there to test the prioritization between muted and threadgated.
762
- await sc.mute(op.did, opMuted.did)
763
-
764
- return {
765
- seedClient: sc,
766
- users,
767
- root,
768
- r,
769
- }
770
- }
771
-
772
- export async function tags(sc: SeedClient<TestNetwork>) {
773
- const users = await createUsers(sc, 'tags', [
774
- 'op',
775
- 'alice',
776
- 'down',
777
- 'following',
778
- 'hide',
779
- 'viewer',
780
- ] as const)
781
-
782
- const { op, alice, down, following, hide, viewer } = users
783
-
784
- const { root, replies: r } = await createThread(sc, op, async (r) => {
785
- await r(alice, async (r) => {
786
- await r(alice)
787
- await r(down)
788
- await r(hide)
789
- })
790
- await r(down, async (r) => {
791
- await r(alice)
792
- await r(down)
793
- await r(hide)
794
- })
795
- await r(hide, async (r) => {
796
- await r(alice)
797
- await r(down)
798
- await r(hide)
799
- })
800
- await r(op)
801
- await r(viewer)
802
- await r(following)
803
- })
804
-
805
- await sc.network.processAll()
806
-
807
- await sc.follow(viewer.did, following.did)
808
-
809
- const db = sc.network.bsky.db.db
810
- await createTag(db, { uri: r['1'].ref.uriStr, val: TAG_BUMP_DOWN })
811
- await createTag(db, { uri: r['0.1'].ref.uriStr, val: TAG_BUMP_DOWN })
812
- await createTag(db, { uri: r['1.1'].ref.uriStr, val: TAG_BUMP_DOWN })
813
- await createTag(db, { uri: r['2.1'].ref.uriStr, val: TAG_BUMP_DOWN })
814
-
815
- await createTag(db, { uri: r['2'].ref.uriStr, val: TAG_HIDE })
816
- await createTag(db, { uri: r['0.2'].ref.uriStr, val: TAG_HIDE })
817
- await createTag(db, { uri: r['1.2'].ref.uriStr, val: TAG_HIDE })
818
- await createTag(db, { uri: r['2.2'].ref.uriStr, val: TAG_HIDE })
819
-
820
- // Neither tag affect op, viewer.
821
- await createTag(db, { uri: r['3'].ref.uriStr, val: TAG_BUMP_DOWN })
822
- await createTag(db, { uri: r['4'].ref.uriStr, val: TAG_HIDE })
823
-
824
- // Tags affect following depending on the config to prioritize following.
825
- await createTag(db, { uri: r['5'].ref.uriStr, val: TAG_HIDE })
826
-
827
- return {
828
- seedClient: sc,
829
- users,
830
- root,
831
- r,
832
- }
833
- }
834
-
835
- const createLabel = async (
836
- db: DatabaseSchema,
837
- opts: {
838
- src: string
839
- uri: string
840
- cid: string
841
- val: string
842
- exp?: string
843
- },
844
- ) => {
845
- await db
846
- .insertInto('label')
847
- .values({
848
- uri: opts.uri,
849
- cid: opts.cid,
850
- val: opts.val,
851
- cts: new Date().toISOString(),
852
- exp: opts.exp ?? null,
853
- neg: false,
854
- src: opts.src,
855
- })
856
- .execute()
857
- }
858
-
859
- const createTag = async (
860
- db: DatabaseSchema,
861
- opts: {
862
- uri: string
863
- val: string
864
- },
865
- ) => {
866
- await db
867
- .updateTable('record')
868
- .set({
869
- tags: sql<string[]>`${JSON.stringify([opts.val])}`,
870
- })
871
- .where('uri', '=', opts.uri)
872
- .returningAll()
873
- .execute()
874
- }