@atproto/bsky 0.0.114 → 0.0.116
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 +16 -0
- package/dist/data-plane/server/util.d.ts.map +1 -1
- package/dist/data-plane/server/util.js +13 -2
- package/dist/data-plane/server/util.js.map +1 -1
- package/dist/lexicon/lexicons.d.ts +14 -4
- package/dist/lexicon/lexicons.d.ts.map +1 -1
- package/dist/lexicon/lexicons.js +7 -0
- package/dist/lexicon/lexicons.js.map +1 -1
- package/dist/lexicon/types/app/bsky/actor/defs.d.ts +1 -1
- package/dist/lexicon/types/app/bsky/actor/defs.d.ts.map +1 -1
- package/dist/lexicon/types/app/bsky/actor/defs.js.map +1 -1
- package/dist/lexicon/types/app/bsky/feed/threadgate.d.ts +7 -1
- package/dist/lexicon/types/app/bsky/feed/threadgate.d.ts.map +1 -1
- package/dist/lexicon/types/app/bsky/feed/threadgate.js +10 -0
- package/dist/lexicon/types/app/bsky/feed/threadgate.js.map +1 -1
- package/dist/views/index.d.ts.map +1 -1
- package/dist/views/index.js +4 -1
- package/dist/views/index.js.map +1 -1
- package/dist/views/util.d.ts +1 -0
- package/dist/views/util.d.ts.map +1 -1
- package/dist/views/util.js +9 -2
- package/dist/views/util.js.map +1 -1
- package/package.json +4 -4
- package/src/data-plane/server/util.ts +12 -1
- package/src/lexicon/lexicons.ts +7 -0
- package/src/lexicon/types/app/bsky/actor/defs.ts +1 -0
- package/src/lexicon/types/app/bsky/feed/threadgate.ts +18 -0
- package/src/views/index.ts +4 -0
- package/src/views/util.ts +11 -2
- package/tests/views/__snapshots__/threadgating.test.ts.snap +21 -0
- package/tests/views/threadgating.test.ts +108 -8
package/src/views/util.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from '../lexicon/types/app/bsky/feed/postgate'
|
|
8
8
|
import {
|
|
9
9
|
Record as GateRecord,
|
|
10
|
+
isFollowerRule,
|
|
10
11
|
isFollowingRule,
|
|
11
12
|
isListRule,
|
|
12
13
|
isMentionRule,
|
|
@@ -28,6 +29,7 @@ export const parseThreadGate = (
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
const allowMentions = gate.allow.some(isMentionRule)
|
|
32
|
+
const allowFollower = gate.allow.some(isFollowerRule)
|
|
31
33
|
const allowFollowing = gate.allow.some(isFollowingRule)
|
|
32
34
|
const allowListUris = gate.allow?.filter(isListRule).map((item) => item.list)
|
|
33
35
|
|
|
@@ -39,15 +41,22 @@ export const parseThreadGate = (
|
|
|
39
41
|
)
|
|
40
42
|
})
|
|
41
43
|
if (isMentioned) {
|
|
42
|
-
return {
|
|
44
|
+
return {
|
|
45
|
+
canReply: true,
|
|
46
|
+
allowMentions,
|
|
47
|
+
allowFollower,
|
|
48
|
+
allowFollowing,
|
|
49
|
+
allowListUris,
|
|
50
|
+
}
|
|
43
51
|
}
|
|
44
52
|
}
|
|
45
|
-
return { allowMentions, allowFollowing, allowListUris }
|
|
53
|
+
return { allowMentions, allowFollower, allowFollowing, allowListUris }
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
type ParsedThreadGate = {
|
|
49
57
|
canReply?: boolean
|
|
50
58
|
allowMentions?: boolean
|
|
59
|
+
allowFollower?: boolean
|
|
51
60
|
allowFollowing?: boolean
|
|
52
61
|
allowListUris?: string[]
|
|
53
62
|
}
|
|
@@ -16,6 +16,24 @@ Object {
|
|
|
16
16
|
}
|
|
17
17
|
`;
|
|
18
18
|
|
|
19
|
+
exports[`views with thread gating applies gate for follower rule. 1`] = `
|
|
20
|
+
Object {
|
|
21
|
+
"cid": "cids(0)",
|
|
22
|
+
"lists": Array [],
|
|
23
|
+
"record": Object {
|
|
24
|
+
"$type": "app.bsky.feed.threadgate",
|
|
25
|
+
"allow": Array [
|
|
26
|
+
Object {
|
|
27
|
+
"$type": "app.bsky.feed.threadgate#followerRule",
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
31
|
+
"post": "record(1)",
|
|
32
|
+
},
|
|
33
|
+
"uri": "record(0)",
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
|
|
19
37
|
exports[`views with thread gating applies gate for following rule. 1`] = `
|
|
20
38
|
Object {
|
|
21
39
|
"cid": "cids(0)",
|
|
@@ -123,6 +141,9 @@ Object {
|
|
|
123
141
|
Object {
|
|
124
142
|
"$type": "app.bsky.feed.threadgate#mentionRule",
|
|
125
143
|
},
|
|
144
|
+
Object {
|
|
145
|
+
"$type": "app.bsky.feed.threadgate#followerRule",
|
|
146
|
+
},
|
|
126
147
|
Object {
|
|
127
148
|
"$type": "app.bsky.feed.threadgate#followingRule",
|
|
128
149
|
},
|
|
@@ -22,6 +22,11 @@ describe('views with thread gating', () => {
|
|
|
22
22
|
pdsAgent = network.pds.getClient()
|
|
23
23
|
sc = network.getSeedClient()
|
|
24
24
|
await basicSeed(sc)
|
|
25
|
+
await sc.createAccount('eve', {
|
|
26
|
+
handle: 'eve.test',
|
|
27
|
+
email: 'eve@eve.com',
|
|
28
|
+
password: 'hunter2',
|
|
29
|
+
})
|
|
25
30
|
await network.processAll()
|
|
26
31
|
})
|
|
27
32
|
|
|
@@ -242,8 +247,72 @@ describe('views with thread gating', () => {
|
|
|
242
247
|
expect(reply.post.uri).toEqual(aliceReply.ref.uriStr)
|
|
243
248
|
})
|
|
244
249
|
|
|
250
|
+
it('applies gate for follower rule.', async () => {
|
|
251
|
+
const post = await sc.post(sc.dids.carol, 'follower rule')
|
|
252
|
+
await pdsAgent.api.app.bsky.feed.threadgate.create(
|
|
253
|
+
{ repo: sc.dids.carol, rkey: post.ref.uri.rkey },
|
|
254
|
+
{
|
|
255
|
+
post: post.ref.uriStr,
|
|
256
|
+
createdAt: iso(),
|
|
257
|
+
allow: [{ $type: 'app.bsky.feed.threadgate#followerRule' }],
|
|
258
|
+
},
|
|
259
|
+
sc.getHeaders(sc.dids.carol),
|
|
260
|
+
)
|
|
261
|
+
await network.processAll()
|
|
262
|
+
|
|
263
|
+
// dan does not follow carol, can't reply
|
|
264
|
+
await sc.reply(
|
|
265
|
+
sc.dids.dan,
|
|
266
|
+
post.ref,
|
|
267
|
+
post.ref,
|
|
268
|
+
'follower rule reply disallow',
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
// alice follows carol, can reply
|
|
272
|
+
const aliceReply = await sc.reply(
|
|
273
|
+
sc.dids.alice,
|
|
274
|
+
post.ref,
|
|
275
|
+
post.ref,
|
|
276
|
+
'follower rule reply allow',
|
|
277
|
+
)
|
|
278
|
+
await network.processAll()
|
|
279
|
+
const {
|
|
280
|
+
data: { thread: danThread },
|
|
281
|
+
} = await agent.api.app.bsky.feed.getPostThread(
|
|
282
|
+
{ uri: post.ref.uriStr },
|
|
283
|
+
{
|
|
284
|
+
headers: await network.serviceHeaders(
|
|
285
|
+
sc.dids.dan,
|
|
286
|
+
ids.AppBskyFeedGetPostThread,
|
|
287
|
+
),
|
|
288
|
+
},
|
|
289
|
+
)
|
|
290
|
+
assert(isThreadViewPost(danThread))
|
|
291
|
+
expect(danThread.post.viewer?.replyDisabled).toBe(true)
|
|
292
|
+
await checkReplyDisabled(post.ref.uriStr, sc.dids.dan, true)
|
|
293
|
+
const {
|
|
294
|
+
data: { thread: aliceThread },
|
|
295
|
+
} = await agent.api.app.bsky.feed.getPostThread(
|
|
296
|
+
{ uri: post.ref.uriStr },
|
|
297
|
+
{
|
|
298
|
+
headers: await network.serviceHeaders(
|
|
299
|
+
sc.dids.alice,
|
|
300
|
+
ids.AppBskyFeedGetPostThread,
|
|
301
|
+
),
|
|
302
|
+
},
|
|
303
|
+
)
|
|
304
|
+
assert(isThreadViewPost(aliceThread))
|
|
305
|
+
expect(forSnapshot(aliceThread.post.threadgate)).toMatchSnapshot()
|
|
306
|
+
expect(aliceThread.post.viewer?.replyDisabled).toBe(false)
|
|
307
|
+
await checkReplyDisabled(post.ref.uriStr, sc.dids.alice, false)
|
|
308
|
+
const [reply, ...otherReplies] = aliceThread.replies ?? []
|
|
309
|
+
assert(isThreadViewPost(reply))
|
|
310
|
+
expect(otherReplies.length).toEqual(0)
|
|
311
|
+
expect(reply.post.uri).toEqual(aliceReply.ref.uriStr)
|
|
312
|
+
})
|
|
313
|
+
|
|
245
314
|
it('applies gate for list rule.', async () => {
|
|
246
|
-
const post = await sc.post(sc.dids.carol, '
|
|
315
|
+
const post = await sc.post(sc.dids.carol, 'list rule')
|
|
247
316
|
// setup lists to allow alice and dan
|
|
248
317
|
const listA = await pdsAgent.api.app.bsky.graph.list.create(
|
|
249
318
|
{ repo: sc.dids.carol },
|
|
@@ -419,14 +488,21 @@ describe('views with thread gating', () => {
|
|
|
419
488
|
createdAt: iso(),
|
|
420
489
|
allow: [
|
|
421
490
|
{ $type: 'app.bsky.feed.threadgate#mentionRule' },
|
|
491
|
+
{ $type: 'app.bsky.feed.threadgate#followerRule' },
|
|
422
492
|
{ $type: 'app.bsky.feed.threadgate#followingRule' },
|
|
423
493
|
],
|
|
424
494
|
},
|
|
425
495
|
sc.getHeaders(sc.dids.carol),
|
|
426
496
|
)
|
|
427
497
|
await network.processAll()
|
|
428
|
-
|
|
429
|
-
await sc.reply(sc.dids.
|
|
498
|
+
|
|
499
|
+
await sc.reply(sc.dids.eve, post.ref, post.ref, 'multi rule reply disallow')
|
|
500
|
+
const bobReply = await sc.reply(
|
|
501
|
+
sc.dids.bob,
|
|
502
|
+
post.ref,
|
|
503
|
+
post.ref,
|
|
504
|
+
'multi rule reply allow (follower)',
|
|
505
|
+
)
|
|
430
506
|
const aliceReply = await sc.reply(
|
|
431
507
|
sc.dids.alice,
|
|
432
508
|
post.ref,
|
|
@@ -440,6 +516,23 @@ describe('views with thread gating', () => {
|
|
|
440
516
|
'multi rule reply allow (mention)',
|
|
441
517
|
)
|
|
442
518
|
await network.processAll()
|
|
519
|
+
|
|
520
|
+
const {
|
|
521
|
+
data: { thread: eveThread },
|
|
522
|
+
} = await agent.api.app.bsky.feed.getPostThread(
|
|
523
|
+
{ uri: post.ref.uriStr },
|
|
524
|
+
{
|
|
525
|
+
headers: await network.serviceHeaders(
|
|
526
|
+
sc.dids.eve,
|
|
527
|
+
ids.AppBskyFeedGetPostThread,
|
|
528
|
+
),
|
|
529
|
+
},
|
|
530
|
+
)
|
|
531
|
+
assert(isThreadViewPost(eveThread))
|
|
532
|
+
// eve cannot interact
|
|
533
|
+
expect(eveThread.post.viewer?.replyDisabled).toBe(true)
|
|
534
|
+
await checkReplyDisabled(post.ref.uriStr, sc.dids.eve, true)
|
|
535
|
+
|
|
443
536
|
const {
|
|
444
537
|
data: { thread: bobThread },
|
|
445
538
|
} = await agent.api.app.bsky.feed.getPostThread(
|
|
@@ -452,8 +545,10 @@ describe('views with thread gating', () => {
|
|
|
452
545
|
},
|
|
453
546
|
)
|
|
454
547
|
assert(isThreadViewPost(bobThread))
|
|
455
|
-
|
|
456
|
-
|
|
548
|
+
// bob follows carol, followers can reply
|
|
549
|
+
expect(bobThread.post.viewer?.replyDisabled).toBe(false)
|
|
550
|
+
await checkReplyDisabled(post.ref.uriStr, sc.dids.bob, false)
|
|
551
|
+
|
|
457
552
|
const {
|
|
458
553
|
data: { thread: aliceThread },
|
|
459
554
|
} = await agent.api.app.bsky.feed.getPostThread(
|
|
@@ -466,8 +561,10 @@ describe('views with thread gating', () => {
|
|
|
466
561
|
},
|
|
467
562
|
)
|
|
468
563
|
assert(isThreadViewPost(aliceThread))
|
|
564
|
+
// carol follows alice, followed users can reply
|
|
469
565
|
expect(aliceThread.post.viewer?.replyDisabled).toBe(false)
|
|
470
566
|
await checkReplyDisabled(post.ref.uriStr, sc.dids.alice, false)
|
|
567
|
+
|
|
471
568
|
const {
|
|
472
569
|
data: { thread: danThread },
|
|
473
570
|
} = await agent.api.app.bsky.feed.getPostThread(
|
|
@@ -481,14 +578,17 @@ describe('views with thread gating', () => {
|
|
|
481
578
|
)
|
|
482
579
|
assert(isThreadViewPost(danThread))
|
|
483
580
|
expect(forSnapshot(danThread.post.threadgate)).toMatchSnapshot()
|
|
581
|
+
// dan was mentioned, mentioned users can reply
|
|
484
582
|
expect(danThread.post.viewer?.replyDisabled).toBe(false)
|
|
485
583
|
await checkReplyDisabled(post.ref.uriStr, sc.dids.dan, false)
|
|
486
|
-
|
|
584
|
+
|
|
585
|
+
const [reply1, reply2, reply3, ...otherReplies] = aliceThread.replies ?? []
|
|
487
586
|
assert(isThreadViewPost(reply1))
|
|
488
587
|
assert(isThreadViewPost(reply2))
|
|
588
|
+
assert(isThreadViewPost(reply3))
|
|
489
589
|
expect(otherReplies.length).toEqual(0)
|
|
490
|
-
expect([reply1.post.uri, reply2.post.uri].sort()).toEqual(
|
|
491
|
-
[aliceReply.ref.uriStr, danReply.ref.uriStr].sort(),
|
|
590
|
+
expect([reply1.post.uri, reply2.post.uri, reply3.post.uri].sort()).toEqual(
|
|
591
|
+
[aliceReply.ref.uriStr, danReply.ref.uriStr, bobReply.ref.uriStr].sort(),
|
|
492
592
|
)
|
|
493
593
|
})
|
|
494
594
|
|