@atproto/api 0.12.4 → 0.12.6
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 +14 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +4 -0
- package/dist/agent.js.map +1 -1
- package/dist/bsky-agent.d.ts +19 -0
- package/dist/bsky-agent.d.ts.map +1 -1
- package/dist/bsky-agent.js +179 -0
- package/dist/bsky-agent.js.map +1 -1
- package/dist/client/lexicons.d.ts +32 -0
- package/dist/client/lexicons.d.ts.map +1 -1
- package/dist/client/lexicons.js +33 -0
- package/dist/client/lexicons.js.map +1 -1
- package/dist/client/types/app/bsky/actor/defs.d.ts +16 -1
- package/dist/client/types/app/bsky/actor/defs.d.ts.map +1 -1
- package/dist/client/types/app/bsky/actor/defs.js +21 -1
- package/dist/client/types/app/bsky/actor/defs.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/util.d.ts +13 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +55 -1
- package/dist/util.js.map +1 -1
- package/package.json +2 -2
- package/src/agent.ts +4 -0
- package/src/bsky-agent.ts +222 -1
- package/src/client/lexicons.ts +33 -0
- package/src/client/types/app/bsky/actor/defs.ts +38 -0
- package/src/types.ts +6 -0
- package/src/util.ts +72 -0
- package/tests/bsky-agent.test.ts +1021 -2
- package/tests/moderation-prefs.test.ts +4 -0
package/tests/bsky-agent.test.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { TestNetworkNoAppView } from '@atproto/dev-env'
|
|
2
|
+
import { TID } from '@atproto/common-web'
|
|
2
3
|
import {
|
|
3
4
|
BskyAgent,
|
|
4
5
|
ComAtprotoRepoPutRecord,
|
|
5
6
|
AppBskyActorProfile,
|
|
6
7
|
DEFAULT_LABEL_SETTINGS,
|
|
7
|
-
} from '
|
|
8
|
+
} from '../src'
|
|
9
|
+
import {
|
|
10
|
+
savedFeedsToUriArrays,
|
|
11
|
+
getSavedFeedType,
|
|
12
|
+
validateSavedFeed,
|
|
13
|
+
} from '../src/util'
|
|
14
|
+
import { AppBskyActorDefs } from '../dist'
|
|
8
15
|
|
|
9
16
|
describe('agent', () => {
|
|
10
17
|
let network: TestNetworkNoAppView
|
|
@@ -237,6 +244,14 @@ describe('agent', () => {
|
|
|
237
244
|
|
|
238
245
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
239
246
|
feeds: { pinned: undefined, saved: undefined },
|
|
247
|
+
savedFeeds: [
|
|
248
|
+
{
|
|
249
|
+
id: expect.any(String),
|
|
250
|
+
pinned: true,
|
|
251
|
+
type: 'timeline',
|
|
252
|
+
value: 'following',
|
|
253
|
+
},
|
|
254
|
+
],
|
|
240
255
|
moderationPrefs: {
|
|
241
256
|
adultContentEnabled: false,
|
|
242
257
|
labels: DEFAULT_LABEL_SETTINGS,
|
|
@@ -266,6 +281,14 @@ describe('agent', () => {
|
|
|
266
281
|
await agent.setAdultContentEnabled(true)
|
|
267
282
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
268
283
|
feeds: { pinned: undefined, saved: undefined },
|
|
284
|
+
savedFeeds: [
|
|
285
|
+
{
|
|
286
|
+
id: expect.any(String),
|
|
287
|
+
pinned: true,
|
|
288
|
+
type: 'timeline',
|
|
289
|
+
value: 'following',
|
|
290
|
+
},
|
|
291
|
+
],
|
|
269
292
|
moderationPrefs: {
|
|
270
293
|
adultContentEnabled: true,
|
|
271
294
|
labels: DEFAULT_LABEL_SETTINGS,
|
|
@@ -295,6 +318,14 @@ describe('agent', () => {
|
|
|
295
318
|
await agent.setAdultContentEnabled(false)
|
|
296
319
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
297
320
|
feeds: { pinned: undefined, saved: undefined },
|
|
321
|
+
savedFeeds: [
|
|
322
|
+
{
|
|
323
|
+
id: expect.any(String),
|
|
324
|
+
pinned: true,
|
|
325
|
+
type: 'timeline',
|
|
326
|
+
value: 'following',
|
|
327
|
+
},
|
|
328
|
+
],
|
|
298
329
|
moderationPrefs: {
|
|
299
330
|
adultContentEnabled: false,
|
|
300
331
|
labels: DEFAULT_LABEL_SETTINGS,
|
|
@@ -324,6 +355,14 @@ describe('agent', () => {
|
|
|
324
355
|
await agent.setContentLabelPref('misinfo', 'hide')
|
|
325
356
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
326
357
|
feeds: { pinned: undefined, saved: undefined },
|
|
358
|
+
savedFeeds: [
|
|
359
|
+
{
|
|
360
|
+
id: expect.any(String),
|
|
361
|
+
pinned: true,
|
|
362
|
+
type: 'timeline',
|
|
363
|
+
value: 'following',
|
|
364
|
+
},
|
|
365
|
+
],
|
|
327
366
|
moderationPrefs: {
|
|
328
367
|
adultContentEnabled: false,
|
|
329
368
|
labels: { ...DEFAULT_LABEL_SETTINGS, misinfo: 'hide' },
|
|
@@ -353,6 +392,14 @@ describe('agent', () => {
|
|
|
353
392
|
await agent.setContentLabelPref('spam', 'ignore')
|
|
354
393
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
355
394
|
feeds: { pinned: undefined, saved: undefined },
|
|
395
|
+
savedFeeds: [
|
|
396
|
+
{
|
|
397
|
+
id: expect.any(String),
|
|
398
|
+
pinned: true,
|
|
399
|
+
type: 'timeline',
|
|
400
|
+
value: 'following',
|
|
401
|
+
},
|
|
402
|
+
],
|
|
356
403
|
moderationPrefs: {
|
|
357
404
|
adultContentEnabled: false,
|
|
358
405
|
labels: {
|
|
@@ -385,6 +432,14 @@ describe('agent', () => {
|
|
|
385
432
|
|
|
386
433
|
await agent.addSavedFeed('at://bob.com/app.bsky.feed.generator/fake')
|
|
387
434
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
435
|
+
savedFeeds: [
|
|
436
|
+
{
|
|
437
|
+
id: expect.any(String),
|
|
438
|
+
pinned: true,
|
|
439
|
+
type: 'timeline',
|
|
440
|
+
value: 'following',
|
|
441
|
+
},
|
|
442
|
+
],
|
|
388
443
|
feeds: {
|
|
389
444
|
pinned: [],
|
|
390
445
|
saved: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
@@ -421,6 +476,14 @@ describe('agent', () => {
|
|
|
421
476
|
|
|
422
477
|
await agent.addPinnedFeed('at://bob.com/app.bsky.feed.generator/fake')
|
|
423
478
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
479
|
+
savedFeeds: [
|
|
480
|
+
{
|
|
481
|
+
id: expect.any(String),
|
|
482
|
+
pinned: true,
|
|
483
|
+
type: 'timeline',
|
|
484
|
+
value: 'following',
|
|
485
|
+
},
|
|
486
|
+
],
|
|
424
487
|
feeds: {
|
|
425
488
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
426
489
|
saved: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
@@ -457,6 +520,14 @@ describe('agent', () => {
|
|
|
457
520
|
|
|
458
521
|
await agent.removePinnedFeed('at://bob.com/app.bsky.feed.generator/fake')
|
|
459
522
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
523
|
+
savedFeeds: [
|
|
524
|
+
{
|
|
525
|
+
id: expect.any(String),
|
|
526
|
+
pinned: true,
|
|
527
|
+
type: 'timeline',
|
|
528
|
+
value: 'following',
|
|
529
|
+
},
|
|
530
|
+
],
|
|
460
531
|
feeds: {
|
|
461
532
|
pinned: [],
|
|
462
533
|
saved: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
@@ -493,6 +564,14 @@ describe('agent', () => {
|
|
|
493
564
|
|
|
494
565
|
await agent.removeSavedFeed('at://bob.com/app.bsky.feed.generator/fake')
|
|
495
566
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
567
|
+
savedFeeds: [
|
|
568
|
+
{
|
|
569
|
+
id: expect.any(String),
|
|
570
|
+
pinned: true,
|
|
571
|
+
type: 'timeline',
|
|
572
|
+
value: 'following',
|
|
573
|
+
},
|
|
574
|
+
],
|
|
496
575
|
feeds: {
|
|
497
576
|
pinned: [],
|
|
498
577
|
saved: [],
|
|
@@ -529,6 +608,14 @@ describe('agent', () => {
|
|
|
529
608
|
|
|
530
609
|
await agent.addPinnedFeed('at://bob.com/app.bsky.feed.generator/fake')
|
|
531
610
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
611
|
+
savedFeeds: [
|
|
612
|
+
{
|
|
613
|
+
id: expect.any(String),
|
|
614
|
+
pinned: true,
|
|
615
|
+
type: 'timeline',
|
|
616
|
+
value: 'following',
|
|
617
|
+
},
|
|
618
|
+
],
|
|
532
619
|
feeds: {
|
|
533
620
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
534
621
|
saved: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
@@ -565,6 +652,14 @@ describe('agent', () => {
|
|
|
565
652
|
|
|
566
653
|
await agent.addPinnedFeed('at://bob.com/app.bsky.feed.generator/fake2')
|
|
567
654
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
655
|
+
savedFeeds: [
|
|
656
|
+
{
|
|
657
|
+
id: expect.any(String),
|
|
658
|
+
pinned: true,
|
|
659
|
+
type: 'timeline',
|
|
660
|
+
value: 'following',
|
|
661
|
+
},
|
|
662
|
+
],
|
|
568
663
|
feeds: {
|
|
569
664
|
pinned: [
|
|
570
665
|
'at://bob.com/app.bsky.feed.generator/fake',
|
|
@@ -607,6 +702,14 @@ describe('agent', () => {
|
|
|
607
702
|
|
|
608
703
|
await agent.removeSavedFeed('at://bob.com/app.bsky.feed.generator/fake')
|
|
609
704
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
705
|
+
savedFeeds: [
|
|
706
|
+
{
|
|
707
|
+
id: expect.any(String),
|
|
708
|
+
pinned: true,
|
|
709
|
+
type: 'timeline',
|
|
710
|
+
value: 'following',
|
|
711
|
+
},
|
|
712
|
+
],
|
|
610
713
|
feeds: {
|
|
611
714
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
612
715
|
saved: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
@@ -643,6 +746,14 @@ describe('agent', () => {
|
|
|
643
746
|
|
|
644
747
|
await agent.setPersonalDetails({ birthDate: '2023-09-11T18:05:42.556Z' })
|
|
645
748
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
749
|
+
savedFeeds: [
|
|
750
|
+
{
|
|
751
|
+
id: expect.any(String),
|
|
752
|
+
pinned: true,
|
|
753
|
+
type: 'timeline',
|
|
754
|
+
value: 'following',
|
|
755
|
+
},
|
|
756
|
+
],
|
|
646
757
|
feeds: {
|
|
647
758
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
648
759
|
saved: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
@@ -679,6 +790,14 @@ describe('agent', () => {
|
|
|
679
790
|
|
|
680
791
|
await agent.setFeedViewPrefs('home', { hideReplies: true })
|
|
681
792
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
793
|
+
savedFeeds: [
|
|
794
|
+
{
|
|
795
|
+
id: expect.any(String),
|
|
796
|
+
pinned: true,
|
|
797
|
+
type: 'timeline',
|
|
798
|
+
value: 'following',
|
|
799
|
+
},
|
|
800
|
+
],
|
|
682
801
|
feeds: {
|
|
683
802
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
684
803
|
saved: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
@@ -715,6 +834,14 @@ describe('agent', () => {
|
|
|
715
834
|
|
|
716
835
|
await agent.setFeedViewPrefs('home', { hideReplies: false })
|
|
717
836
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
837
|
+
savedFeeds: [
|
|
838
|
+
{
|
|
839
|
+
id: expect.any(String),
|
|
840
|
+
pinned: true,
|
|
841
|
+
type: 'timeline',
|
|
842
|
+
value: 'following',
|
|
843
|
+
},
|
|
844
|
+
],
|
|
718
845
|
feeds: {
|
|
719
846
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
720
847
|
saved: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
@@ -751,6 +878,14 @@ describe('agent', () => {
|
|
|
751
878
|
|
|
752
879
|
await agent.setFeedViewPrefs('other', { hideReplies: true })
|
|
753
880
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
881
|
+
savedFeeds: [
|
|
882
|
+
{
|
|
883
|
+
id: expect.any(String),
|
|
884
|
+
pinned: true,
|
|
885
|
+
type: 'timeline',
|
|
886
|
+
value: 'following',
|
|
887
|
+
},
|
|
888
|
+
],
|
|
754
889
|
feeds: {
|
|
755
890
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
756
891
|
saved: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
@@ -794,6 +929,14 @@ describe('agent', () => {
|
|
|
794
929
|
|
|
795
930
|
await agent.setThreadViewPrefs({ sort: 'random' })
|
|
796
931
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
932
|
+
savedFeeds: [
|
|
933
|
+
{
|
|
934
|
+
id: expect.any(String),
|
|
935
|
+
pinned: true,
|
|
936
|
+
type: 'timeline',
|
|
937
|
+
value: 'following',
|
|
938
|
+
},
|
|
939
|
+
],
|
|
797
940
|
feeds: {
|
|
798
941
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
799
942
|
saved: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
@@ -837,6 +980,14 @@ describe('agent', () => {
|
|
|
837
980
|
|
|
838
981
|
await agent.setThreadViewPrefs({ sort: 'oldest' })
|
|
839
982
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
983
|
+
savedFeeds: [
|
|
984
|
+
{
|
|
985
|
+
id: expect.any(String),
|
|
986
|
+
pinned: true,
|
|
987
|
+
type: 'timeline',
|
|
988
|
+
value: 'following',
|
|
989
|
+
},
|
|
990
|
+
],
|
|
840
991
|
feeds: {
|
|
841
992
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
842
993
|
saved: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
@@ -880,6 +1031,14 @@ describe('agent', () => {
|
|
|
880
1031
|
|
|
881
1032
|
await agent.setInterestsPref({ tags: ['foo', 'bar'] })
|
|
882
1033
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
1034
|
+
savedFeeds: [
|
|
1035
|
+
{
|
|
1036
|
+
id: expect.any(String),
|
|
1037
|
+
pinned: true,
|
|
1038
|
+
type: 'timeline',
|
|
1039
|
+
value: 'following',
|
|
1040
|
+
},
|
|
1041
|
+
],
|
|
883
1042
|
feeds: {
|
|
884
1043
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
885
1044
|
saved: ['at://bob.com/app.bsky.feed.generator/fake2'],
|
|
@@ -1039,6 +1198,14 @@ describe('agent', () => {
|
|
|
1039
1198
|
],
|
|
1040
1199
|
})
|
|
1041
1200
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
1201
|
+
savedFeeds: [
|
|
1202
|
+
{
|
|
1203
|
+
id: expect.any(String),
|
|
1204
|
+
type: 'timeline',
|
|
1205
|
+
value: 'following',
|
|
1206
|
+
pinned: true,
|
|
1207
|
+
},
|
|
1208
|
+
],
|
|
1042
1209
|
feeds: {
|
|
1043
1210
|
pinned: [],
|
|
1044
1211
|
saved: [],
|
|
@@ -1084,6 +1251,14 @@ describe('agent', () => {
|
|
|
1084
1251
|
|
|
1085
1252
|
await agent.setAdultContentEnabled(false)
|
|
1086
1253
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
1254
|
+
savedFeeds: [
|
|
1255
|
+
{
|
|
1256
|
+
id: expect.any(String),
|
|
1257
|
+
type: 'timeline',
|
|
1258
|
+
value: 'following',
|
|
1259
|
+
pinned: true,
|
|
1260
|
+
},
|
|
1261
|
+
],
|
|
1087
1262
|
feeds: {
|
|
1088
1263
|
pinned: [],
|
|
1089
1264
|
saved: [],
|
|
@@ -1129,6 +1304,14 @@ describe('agent', () => {
|
|
|
1129
1304
|
|
|
1130
1305
|
await agent.setContentLabelPref('porn', 'ignore')
|
|
1131
1306
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
1307
|
+
savedFeeds: [
|
|
1308
|
+
{
|
|
1309
|
+
id: expect.any(String),
|
|
1310
|
+
type: 'timeline',
|
|
1311
|
+
value: 'following',
|
|
1312
|
+
pinned: true,
|
|
1313
|
+
},
|
|
1314
|
+
],
|
|
1132
1315
|
feeds: {
|
|
1133
1316
|
pinned: [],
|
|
1134
1317
|
saved: [],
|
|
@@ -1175,6 +1358,14 @@ describe('agent', () => {
|
|
|
1175
1358
|
|
|
1176
1359
|
await agent.removeLabeler('did:plc:other')
|
|
1177
1360
|
await expect(agent.getPreferences()).resolves.toStrictEqual({
|
|
1361
|
+
savedFeeds: [
|
|
1362
|
+
{
|
|
1363
|
+
id: expect.any(String),
|
|
1364
|
+
type: 'timeline',
|
|
1365
|
+
value: 'following',
|
|
1366
|
+
pinned: true,
|
|
1367
|
+
},
|
|
1368
|
+
],
|
|
1178
1369
|
feeds: {
|
|
1179
1370
|
pinned: [],
|
|
1180
1371
|
saved: [],
|
|
@@ -1221,6 +1412,14 @@ describe('agent', () => {
|
|
|
1221
1412
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
1222
1413
|
saved: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
1223
1414
|
},
|
|
1415
|
+
savedFeeds: [
|
|
1416
|
+
{
|
|
1417
|
+
id: expect.any(String),
|
|
1418
|
+
pinned: true,
|
|
1419
|
+
type: 'timeline',
|
|
1420
|
+
value: 'following',
|
|
1421
|
+
},
|
|
1422
|
+
],
|
|
1224
1423
|
moderationPrefs: {
|
|
1225
1424
|
adultContentEnabled: false,
|
|
1226
1425
|
labels: {
|
|
@@ -1263,6 +1462,14 @@ describe('agent', () => {
|
|
|
1263
1462
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
1264
1463
|
saved: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
1265
1464
|
},
|
|
1465
|
+
savedFeeds: [
|
|
1466
|
+
{
|
|
1467
|
+
id: expect.any(String),
|
|
1468
|
+
pinned: true,
|
|
1469
|
+
type: 'timeline',
|
|
1470
|
+
value: 'following',
|
|
1471
|
+
},
|
|
1472
|
+
],
|
|
1266
1473
|
moderationPrefs: {
|
|
1267
1474
|
adultContentEnabled: false,
|
|
1268
1475
|
labels: {
|
|
@@ -1316,6 +1523,14 @@ describe('agent', () => {
|
|
|
1316
1523
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
1317
1524
|
saved: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
1318
1525
|
},
|
|
1526
|
+
savedFeeds: [
|
|
1527
|
+
{
|
|
1528
|
+
id: expect.any(String),
|
|
1529
|
+
pinned: true,
|
|
1530
|
+
type: 'timeline',
|
|
1531
|
+
value: 'following',
|
|
1532
|
+
},
|
|
1533
|
+
],
|
|
1319
1534
|
moderationPrefs: {
|
|
1320
1535
|
adultContentEnabled: false,
|
|
1321
1536
|
labels: {
|
|
@@ -1353,7 +1568,7 @@ describe('agent', () => {
|
|
|
1353
1568
|
})
|
|
1354
1569
|
|
|
1355
1570
|
const res = await agent.app.bsky.actor.getPreferences()
|
|
1356
|
-
|
|
1571
|
+
expect(res.data.preferences.sort(byType)).toStrictEqual(
|
|
1357
1572
|
[
|
|
1358
1573
|
{
|
|
1359
1574
|
$type: 'app.bsky.actor.defs#adultContentPref',
|
|
@@ -1382,6 +1597,17 @@ describe('agent', () => {
|
|
|
1382
1597
|
pinned: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
1383
1598
|
saved: ['at://bob.com/app.bsky.feed.generator/fake'],
|
|
1384
1599
|
},
|
|
1600
|
+
{
|
|
1601
|
+
$type: 'app.bsky.actor.defs#savedFeedsPrefV2',
|
|
1602
|
+
items: [
|
|
1603
|
+
{
|
|
1604
|
+
id: expect.any(String),
|
|
1605
|
+
pinned: true,
|
|
1606
|
+
type: 'timeline',
|
|
1607
|
+
value: 'following',
|
|
1608
|
+
},
|
|
1609
|
+
],
|
|
1610
|
+
},
|
|
1385
1611
|
{
|
|
1386
1612
|
$type: 'app.bsky.actor.defs#personalDetailsPref',
|
|
1387
1613
|
birthDate: '2023-09-11T18:05:42.556Z',
|
|
@@ -1674,6 +1900,799 @@ describe('agent', () => {
|
|
|
1674
1900
|
})
|
|
1675
1901
|
})
|
|
1676
1902
|
|
|
1903
|
+
describe(`saved feeds v2`, () => {
|
|
1904
|
+
let agent: BskyAgent
|
|
1905
|
+
let i = 0
|
|
1906
|
+
const feedUri = () => `at://bob.com/app.bsky.feed.generator/${i++}`
|
|
1907
|
+
const listUri = () => `at://bob.com/app.bsky.graph.list/${i++}`
|
|
1908
|
+
|
|
1909
|
+
beforeAll(async () => {
|
|
1910
|
+
agent = new BskyAgent({ service: network.pds.url })
|
|
1911
|
+
await agent.createAccount({
|
|
1912
|
+
handle: 'user9.test',
|
|
1913
|
+
email: 'user9@test.com',
|
|
1914
|
+
password: 'password',
|
|
1915
|
+
})
|
|
1916
|
+
})
|
|
1917
|
+
|
|
1918
|
+
beforeEach(async () => {
|
|
1919
|
+
await agent.app.bsky.actor.putPreferences({
|
|
1920
|
+
preferences: [],
|
|
1921
|
+
})
|
|
1922
|
+
})
|
|
1923
|
+
|
|
1924
|
+
describe(`addSavedFeeds`, () => {
|
|
1925
|
+
it('works', async () => {
|
|
1926
|
+
const feed = {
|
|
1927
|
+
type: 'feed',
|
|
1928
|
+
value: feedUri(),
|
|
1929
|
+
pinned: false,
|
|
1930
|
+
}
|
|
1931
|
+
await agent.addSavedFeeds([feed])
|
|
1932
|
+
const prefs = await agent.getPreferences()
|
|
1933
|
+
expect(prefs.savedFeeds).toStrictEqual([
|
|
1934
|
+
{
|
|
1935
|
+
...feed,
|
|
1936
|
+
id: expect.any(String),
|
|
1937
|
+
},
|
|
1938
|
+
])
|
|
1939
|
+
})
|
|
1940
|
+
|
|
1941
|
+
it('throws if feed is specified and list provided', async () => {
|
|
1942
|
+
const list = listUri()
|
|
1943
|
+
await expect(() =>
|
|
1944
|
+
agent.addSavedFeeds([
|
|
1945
|
+
{
|
|
1946
|
+
type: 'feed',
|
|
1947
|
+
value: list,
|
|
1948
|
+
pinned: true,
|
|
1949
|
+
},
|
|
1950
|
+
]),
|
|
1951
|
+
).rejects.toThrow()
|
|
1952
|
+
})
|
|
1953
|
+
|
|
1954
|
+
it('throws if list is specified and feed provided', async () => {
|
|
1955
|
+
const feed = feedUri()
|
|
1956
|
+
await expect(() =>
|
|
1957
|
+
agent.addSavedFeeds([
|
|
1958
|
+
{
|
|
1959
|
+
type: 'list',
|
|
1960
|
+
value: feed,
|
|
1961
|
+
pinned: true,
|
|
1962
|
+
},
|
|
1963
|
+
]),
|
|
1964
|
+
).rejects.toThrow()
|
|
1965
|
+
})
|
|
1966
|
+
|
|
1967
|
+
it(`timeline`, async () => {
|
|
1968
|
+
const feeds = await agent.addSavedFeeds([
|
|
1969
|
+
{
|
|
1970
|
+
type: 'timeline',
|
|
1971
|
+
value: 'following',
|
|
1972
|
+
pinned: true,
|
|
1973
|
+
},
|
|
1974
|
+
])
|
|
1975
|
+
const prefs = await agent.getPreferences()
|
|
1976
|
+
expect(
|
|
1977
|
+
prefs.savedFeeds.filter((f) => f.type === 'timeline'),
|
|
1978
|
+
).toStrictEqual(feeds)
|
|
1979
|
+
})
|
|
1980
|
+
|
|
1981
|
+
it(`allows duplicates`, async () => {
|
|
1982
|
+
const feed = {
|
|
1983
|
+
type: 'feed',
|
|
1984
|
+
value: feedUri(),
|
|
1985
|
+
pinned: false,
|
|
1986
|
+
}
|
|
1987
|
+
await agent.addSavedFeeds([feed])
|
|
1988
|
+
await agent.addSavedFeeds([feed])
|
|
1989
|
+
const prefs = await agent.getPreferences()
|
|
1990
|
+
expect(prefs.savedFeeds).toStrictEqual([
|
|
1991
|
+
{
|
|
1992
|
+
...feed,
|
|
1993
|
+
id: expect.any(String),
|
|
1994
|
+
},
|
|
1995
|
+
{
|
|
1996
|
+
...feed,
|
|
1997
|
+
id: expect.any(String),
|
|
1998
|
+
},
|
|
1999
|
+
])
|
|
2000
|
+
})
|
|
2001
|
+
|
|
2002
|
+
it(`adds multiple`, async () => {
|
|
2003
|
+
const a = {
|
|
2004
|
+
type: 'feed',
|
|
2005
|
+
value: feedUri(),
|
|
2006
|
+
pinned: true,
|
|
2007
|
+
}
|
|
2008
|
+
const b = {
|
|
2009
|
+
type: 'feed',
|
|
2010
|
+
value: feedUri(),
|
|
2011
|
+
pinned: false,
|
|
2012
|
+
}
|
|
2013
|
+
await agent.addSavedFeeds([a, b])
|
|
2014
|
+
const prefs = await agent.getPreferences()
|
|
2015
|
+
expect(prefs.savedFeeds).toStrictEqual([
|
|
2016
|
+
{
|
|
2017
|
+
...a,
|
|
2018
|
+
id: expect.any(String),
|
|
2019
|
+
},
|
|
2020
|
+
{
|
|
2021
|
+
...b,
|
|
2022
|
+
id: expect.any(String),
|
|
2023
|
+
},
|
|
2024
|
+
])
|
|
2025
|
+
})
|
|
2026
|
+
|
|
2027
|
+
it(`appends multiple`, async () => {
|
|
2028
|
+
const a = {
|
|
2029
|
+
type: 'feed',
|
|
2030
|
+
value: feedUri(),
|
|
2031
|
+
pinned: true,
|
|
2032
|
+
}
|
|
2033
|
+
const b = {
|
|
2034
|
+
type: 'feed',
|
|
2035
|
+
value: feedUri(),
|
|
2036
|
+
pinned: false,
|
|
2037
|
+
}
|
|
2038
|
+
const c = {
|
|
2039
|
+
type: 'feed',
|
|
2040
|
+
value: feedUri(),
|
|
2041
|
+
pinned: true,
|
|
2042
|
+
}
|
|
2043
|
+
const d = {
|
|
2044
|
+
type: 'feed',
|
|
2045
|
+
value: feedUri(),
|
|
2046
|
+
pinned: false,
|
|
2047
|
+
}
|
|
2048
|
+
await agent.addSavedFeeds([a, b])
|
|
2049
|
+
await agent.addSavedFeeds([c, d])
|
|
2050
|
+
const prefs = await agent.getPreferences()
|
|
2051
|
+
expect(prefs.savedFeeds).toStrictEqual([
|
|
2052
|
+
{
|
|
2053
|
+
...a,
|
|
2054
|
+
id: expect.any(String),
|
|
2055
|
+
},
|
|
2056
|
+
{
|
|
2057
|
+
...c,
|
|
2058
|
+
id: expect.any(String),
|
|
2059
|
+
},
|
|
2060
|
+
{
|
|
2061
|
+
...b,
|
|
2062
|
+
id: expect.any(String),
|
|
2063
|
+
},
|
|
2064
|
+
{
|
|
2065
|
+
...d,
|
|
2066
|
+
id: expect.any(String),
|
|
2067
|
+
},
|
|
2068
|
+
])
|
|
2069
|
+
})
|
|
2070
|
+
})
|
|
2071
|
+
|
|
2072
|
+
describe(`removeSavedFeeds`, () => {
|
|
2073
|
+
it('works', async () => {
|
|
2074
|
+
const feed = {
|
|
2075
|
+
type: 'feed',
|
|
2076
|
+
value: feedUri(),
|
|
2077
|
+
pinned: true,
|
|
2078
|
+
}
|
|
2079
|
+
const savedFeeds = await agent.addSavedFeeds([feed])
|
|
2080
|
+
await agent.removeSavedFeeds([savedFeeds[0].id])
|
|
2081
|
+
const prefs = await agent.getPreferences()
|
|
2082
|
+
expect(prefs.savedFeeds).toStrictEqual([])
|
|
2083
|
+
})
|
|
2084
|
+
})
|
|
2085
|
+
|
|
2086
|
+
describe(`overwriteSavedFeeds`, () => {
|
|
2087
|
+
it(`dedupes by id, takes last, preserves order based on last found`, async () => {
|
|
2088
|
+
const a = {
|
|
2089
|
+
id: TID.nextStr(),
|
|
2090
|
+
type: 'feed',
|
|
2091
|
+
value: feedUri(),
|
|
2092
|
+
pinned: true,
|
|
2093
|
+
}
|
|
2094
|
+
const b = {
|
|
2095
|
+
id: TID.nextStr(),
|
|
2096
|
+
type: 'feed',
|
|
2097
|
+
value: feedUri(),
|
|
2098
|
+
pinned: true,
|
|
2099
|
+
}
|
|
2100
|
+
await agent.overwriteSavedFeeds([a, b, a])
|
|
2101
|
+
const prefs = await agent.getPreferences()
|
|
2102
|
+
expect(prefs.savedFeeds).toStrictEqual([b, a])
|
|
2103
|
+
})
|
|
2104
|
+
|
|
2105
|
+
it(`preserves order`, async () => {
|
|
2106
|
+
const a = feedUri()
|
|
2107
|
+
const b = feedUri()
|
|
2108
|
+
const c = feedUri()
|
|
2109
|
+
const d = feedUri()
|
|
2110
|
+
|
|
2111
|
+
await agent.overwriteSavedFeeds([
|
|
2112
|
+
{
|
|
2113
|
+
id: TID.nextStr(),
|
|
2114
|
+
type: 'timeline',
|
|
2115
|
+
value: a,
|
|
2116
|
+
pinned: true,
|
|
2117
|
+
},
|
|
2118
|
+
{
|
|
2119
|
+
id: TID.nextStr(),
|
|
2120
|
+
type: 'feed',
|
|
2121
|
+
value: b,
|
|
2122
|
+
pinned: false,
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
id: TID.nextStr(),
|
|
2126
|
+
type: 'feed',
|
|
2127
|
+
value: c,
|
|
2128
|
+
pinned: true,
|
|
2129
|
+
},
|
|
2130
|
+
{
|
|
2131
|
+
id: TID.nextStr(),
|
|
2132
|
+
type: 'feed',
|
|
2133
|
+
value: d,
|
|
2134
|
+
pinned: false,
|
|
2135
|
+
},
|
|
2136
|
+
])
|
|
2137
|
+
|
|
2138
|
+
const { savedFeeds } = await agent.getPreferences()
|
|
2139
|
+
expect(savedFeeds.filter((f) => f.pinned)).toStrictEqual([
|
|
2140
|
+
{
|
|
2141
|
+
id: expect.any(String),
|
|
2142
|
+
type: 'timeline',
|
|
2143
|
+
value: a,
|
|
2144
|
+
pinned: true,
|
|
2145
|
+
},
|
|
2146
|
+
{
|
|
2147
|
+
id: expect.any(String),
|
|
2148
|
+
type: 'feed',
|
|
2149
|
+
value: c,
|
|
2150
|
+
pinned: true,
|
|
2151
|
+
},
|
|
2152
|
+
])
|
|
2153
|
+
expect(savedFeeds.filter((f) => !f.pinned)).toEqual([
|
|
2154
|
+
{
|
|
2155
|
+
id: expect.any(String),
|
|
2156
|
+
type: 'feed',
|
|
2157
|
+
value: b,
|
|
2158
|
+
pinned: false,
|
|
2159
|
+
},
|
|
2160
|
+
{
|
|
2161
|
+
id: expect.any(String),
|
|
2162
|
+
type: 'feed',
|
|
2163
|
+
value: d,
|
|
2164
|
+
pinned: false,
|
|
2165
|
+
},
|
|
2166
|
+
])
|
|
2167
|
+
})
|
|
2168
|
+
})
|
|
2169
|
+
|
|
2170
|
+
describe(`updateSavedFeeds`, () => {
|
|
2171
|
+
it(`updates affect order, saved last, new pins last`, async () => {
|
|
2172
|
+
const a = {
|
|
2173
|
+
id: TID.nextStr(),
|
|
2174
|
+
type: 'feed',
|
|
2175
|
+
value: feedUri(),
|
|
2176
|
+
pinned: true,
|
|
2177
|
+
}
|
|
2178
|
+
const b = {
|
|
2179
|
+
id: TID.nextStr(),
|
|
2180
|
+
type: 'feed',
|
|
2181
|
+
value: feedUri(),
|
|
2182
|
+
pinned: true,
|
|
2183
|
+
}
|
|
2184
|
+
const c = {
|
|
2185
|
+
id: TID.nextStr(),
|
|
2186
|
+
type: 'feed',
|
|
2187
|
+
value: feedUri(),
|
|
2188
|
+
pinned: true,
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
await agent.overwriteSavedFeeds([a, b, c])
|
|
2192
|
+
await agent.updateSavedFeeds([
|
|
2193
|
+
{
|
|
2194
|
+
...b,
|
|
2195
|
+
pinned: false,
|
|
2196
|
+
},
|
|
2197
|
+
])
|
|
2198
|
+
|
|
2199
|
+
const prefs1 = await agent.getPreferences()
|
|
2200
|
+
expect(prefs1.savedFeeds).toStrictEqual([
|
|
2201
|
+
a,
|
|
2202
|
+
c,
|
|
2203
|
+
{
|
|
2204
|
+
...b,
|
|
2205
|
+
pinned: false,
|
|
2206
|
+
},
|
|
2207
|
+
])
|
|
2208
|
+
|
|
2209
|
+
await agent.updateSavedFeeds([
|
|
2210
|
+
{
|
|
2211
|
+
...b,
|
|
2212
|
+
pinned: true,
|
|
2213
|
+
},
|
|
2214
|
+
])
|
|
2215
|
+
|
|
2216
|
+
const prefs2 = await agent.getPreferences()
|
|
2217
|
+
expect(prefs2.savedFeeds).toStrictEqual([a, c, b])
|
|
2218
|
+
})
|
|
2219
|
+
|
|
2220
|
+
it(`cannot override original id`, async () => {
|
|
2221
|
+
const a = {
|
|
2222
|
+
id: TID.nextStr(),
|
|
2223
|
+
type: 'feed',
|
|
2224
|
+
value: feedUri(),
|
|
2225
|
+
pinned: true,
|
|
2226
|
+
}
|
|
2227
|
+
await agent.overwriteSavedFeeds([a])
|
|
2228
|
+
await agent.updateSavedFeeds([
|
|
2229
|
+
{
|
|
2230
|
+
...a,
|
|
2231
|
+
pinned: false,
|
|
2232
|
+
id: TID.nextStr(),
|
|
2233
|
+
},
|
|
2234
|
+
])
|
|
2235
|
+
const prefs = await agent.getPreferences()
|
|
2236
|
+
expect(prefs.savedFeeds).toStrictEqual([a])
|
|
2237
|
+
})
|
|
2238
|
+
|
|
2239
|
+
it(`updates multiple`, async () => {
|
|
2240
|
+
const a = {
|
|
2241
|
+
id: TID.nextStr(),
|
|
2242
|
+
type: 'feed',
|
|
2243
|
+
value: feedUri(),
|
|
2244
|
+
pinned: false,
|
|
2245
|
+
}
|
|
2246
|
+
const b = {
|
|
2247
|
+
id: TID.nextStr(),
|
|
2248
|
+
type: 'feed',
|
|
2249
|
+
value: feedUri(),
|
|
2250
|
+
pinned: false,
|
|
2251
|
+
}
|
|
2252
|
+
const c = {
|
|
2253
|
+
id: TID.nextStr(),
|
|
2254
|
+
type: 'feed',
|
|
2255
|
+
value: feedUri(),
|
|
2256
|
+
pinned: false,
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2259
|
+
await agent.overwriteSavedFeeds([a, b, c])
|
|
2260
|
+
await agent.updateSavedFeeds([
|
|
2261
|
+
{
|
|
2262
|
+
...b,
|
|
2263
|
+
pinned: true,
|
|
2264
|
+
},
|
|
2265
|
+
{
|
|
2266
|
+
...c,
|
|
2267
|
+
pinned: true,
|
|
2268
|
+
},
|
|
2269
|
+
])
|
|
2270
|
+
|
|
2271
|
+
const prefs1 = await agent.getPreferences()
|
|
2272
|
+
expect(prefs1.savedFeeds).toStrictEqual([
|
|
2273
|
+
{
|
|
2274
|
+
...b,
|
|
2275
|
+
pinned: true,
|
|
2276
|
+
},
|
|
2277
|
+
{
|
|
2278
|
+
...c,
|
|
2279
|
+
pinned: true,
|
|
2280
|
+
},
|
|
2281
|
+
a,
|
|
2282
|
+
])
|
|
2283
|
+
})
|
|
2284
|
+
})
|
|
2285
|
+
|
|
2286
|
+
describe(`utils`, () => {
|
|
2287
|
+
describe(`savedFeedsToUriArrays`, () => {
|
|
2288
|
+
const { saved, pinned } = savedFeedsToUriArrays([
|
|
2289
|
+
{
|
|
2290
|
+
id: '',
|
|
2291
|
+
type: 'feed',
|
|
2292
|
+
value: 'a',
|
|
2293
|
+
pinned: true,
|
|
2294
|
+
},
|
|
2295
|
+
{
|
|
2296
|
+
id: '',
|
|
2297
|
+
type: 'feed',
|
|
2298
|
+
value: 'b',
|
|
2299
|
+
pinned: false,
|
|
2300
|
+
},
|
|
2301
|
+
{
|
|
2302
|
+
id: '',
|
|
2303
|
+
type: 'feed',
|
|
2304
|
+
value: 'c',
|
|
2305
|
+
pinned: true,
|
|
2306
|
+
},
|
|
2307
|
+
])
|
|
2308
|
+
expect(saved).toStrictEqual(['a', 'b', 'c'])
|
|
2309
|
+
expect(pinned).toStrictEqual(['a', 'c'])
|
|
2310
|
+
})
|
|
2311
|
+
|
|
2312
|
+
describe(`getSavedFeedType`, () => {
|
|
2313
|
+
it(`works`, () => {
|
|
2314
|
+
expect(getSavedFeedType('foo')).toBe('unknown')
|
|
2315
|
+
expect(getSavedFeedType(feedUri())).toBe('feed')
|
|
2316
|
+
expect(getSavedFeedType(listUri())).toBe('list')
|
|
2317
|
+
expect(
|
|
2318
|
+
getSavedFeedType('at://did:plc:fake/app.bsky.graph.follow/fake'),
|
|
2319
|
+
).toBe('unknown')
|
|
2320
|
+
})
|
|
2321
|
+
})
|
|
2322
|
+
|
|
2323
|
+
describe(`validateSavedFeed`, () => {
|
|
2324
|
+
it(`throws if invalid TID`, () => {
|
|
2325
|
+
// really only checks length at time of writing
|
|
2326
|
+
expect(() =>
|
|
2327
|
+
validateSavedFeed({
|
|
2328
|
+
id: 'a',
|
|
2329
|
+
type: 'feed',
|
|
2330
|
+
value: feedUri(),
|
|
2331
|
+
pinned: false,
|
|
2332
|
+
}),
|
|
2333
|
+
).toThrow()
|
|
2334
|
+
})
|
|
2335
|
+
|
|
2336
|
+
it(`throws if mismatched types`, () => {
|
|
2337
|
+
expect(() =>
|
|
2338
|
+
validateSavedFeed({
|
|
2339
|
+
id: TID.nextStr(),
|
|
2340
|
+
type: 'list',
|
|
2341
|
+
value: feedUri(),
|
|
2342
|
+
pinned: false,
|
|
2343
|
+
}),
|
|
2344
|
+
).toThrow()
|
|
2345
|
+
expect(() =>
|
|
2346
|
+
validateSavedFeed({
|
|
2347
|
+
id: TID.nextStr(),
|
|
2348
|
+
type: 'feed',
|
|
2349
|
+
value: listUri(),
|
|
2350
|
+
pinned: false,
|
|
2351
|
+
}),
|
|
2352
|
+
).toThrow()
|
|
2353
|
+
})
|
|
2354
|
+
|
|
2355
|
+
it(`ignores values it can't validate`, () => {
|
|
2356
|
+
expect(() =>
|
|
2357
|
+
validateSavedFeed({
|
|
2358
|
+
id: TID.nextStr(),
|
|
2359
|
+
type: 'timeline',
|
|
2360
|
+
value: 'following',
|
|
2361
|
+
pinned: false,
|
|
2362
|
+
}),
|
|
2363
|
+
).not.toThrow()
|
|
2364
|
+
expect(() =>
|
|
2365
|
+
validateSavedFeed({
|
|
2366
|
+
id: TID.nextStr(),
|
|
2367
|
+
type: 'unknown',
|
|
2368
|
+
value: 'could be @nyt4!ng',
|
|
2369
|
+
pinned: false,
|
|
2370
|
+
}),
|
|
2371
|
+
).not.toThrow()
|
|
2372
|
+
})
|
|
2373
|
+
})
|
|
2374
|
+
})
|
|
2375
|
+
})
|
|
2376
|
+
|
|
2377
|
+
describe(`saved feeds v2: migration scenarios`, () => {
|
|
2378
|
+
let agent: BskyAgent
|
|
2379
|
+
let i = 0
|
|
2380
|
+
const feedUri = () => `at://bob.com/app.bsky.feed.generator/${i++}`
|
|
2381
|
+
|
|
2382
|
+
beforeAll(async () => {
|
|
2383
|
+
agent = new BskyAgent({ service: network.pds.url })
|
|
2384
|
+
await agent.createAccount({
|
|
2385
|
+
handle: 'user10.test',
|
|
2386
|
+
email: 'user10@test.com',
|
|
2387
|
+
password: 'password',
|
|
2388
|
+
})
|
|
2389
|
+
})
|
|
2390
|
+
|
|
2391
|
+
beforeEach(async () => {
|
|
2392
|
+
await agent.app.bsky.actor.putPreferences({
|
|
2393
|
+
preferences: [],
|
|
2394
|
+
})
|
|
2395
|
+
})
|
|
2396
|
+
|
|
2397
|
+
it('CRUD action before migration, no timeline inserted', async () => {
|
|
2398
|
+
const feed = {
|
|
2399
|
+
type: 'feed',
|
|
2400
|
+
value: feedUri(),
|
|
2401
|
+
pinned: false,
|
|
2402
|
+
}
|
|
2403
|
+
await agent.addSavedFeeds([feed])
|
|
2404
|
+
const prefs = await agent.getPreferences()
|
|
2405
|
+
expect(prefs.savedFeeds).toStrictEqual([
|
|
2406
|
+
{
|
|
2407
|
+
...feed,
|
|
2408
|
+
id: expect.any(String),
|
|
2409
|
+
},
|
|
2410
|
+
])
|
|
2411
|
+
})
|
|
2412
|
+
|
|
2413
|
+
it('CRUD action AFTER migration, timeline was inserted', async () => {
|
|
2414
|
+
await agent.getPreferences()
|
|
2415
|
+
const feed = {
|
|
2416
|
+
type: 'feed',
|
|
2417
|
+
value: feedUri(),
|
|
2418
|
+
pinned: false,
|
|
2419
|
+
}
|
|
2420
|
+
await agent.addSavedFeeds([feed])
|
|
2421
|
+
const prefs = await agent.getPreferences()
|
|
2422
|
+
expect(prefs.savedFeeds).toStrictEqual([
|
|
2423
|
+
{
|
|
2424
|
+
id: expect.any(String),
|
|
2425
|
+
type: 'timeline',
|
|
2426
|
+
value: 'following',
|
|
2427
|
+
pinned: true,
|
|
2428
|
+
},
|
|
2429
|
+
{
|
|
2430
|
+
...feed,
|
|
2431
|
+
id: expect.any(String),
|
|
2432
|
+
},
|
|
2433
|
+
])
|
|
2434
|
+
})
|
|
2435
|
+
|
|
2436
|
+
// fresh account OR an old account with no v1 prefs to migrate from
|
|
2437
|
+
it(`brand new user, v1 remains undefined`, async () => {
|
|
2438
|
+
const prefs = await agent.getPreferences()
|
|
2439
|
+
expect(prefs.savedFeeds).toStrictEqual([
|
|
2440
|
+
{
|
|
2441
|
+
id: expect.any(String),
|
|
2442
|
+
type: 'timeline',
|
|
2443
|
+
value: 'following',
|
|
2444
|
+
pinned: true,
|
|
2445
|
+
},
|
|
2446
|
+
])
|
|
2447
|
+
// no v1 prefs to populate from
|
|
2448
|
+
expect(prefs.feeds).toStrictEqual({
|
|
2449
|
+
saved: undefined,
|
|
2450
|
+
pinned: undefined,
|
|
2451
|
+
})
|
|
2452
|
+
})
|
|
2453
|
+
|
|
2454
|
+
it(`brand new user, v2 does not write to v1`, async () => {
|
|
2455
|
+
const a = feedUri()
|
|
2456
|
+
// migration happens
|
|
2457
|
+
await agent.getPreferences()
|
|
2458
|
+
await agent.addSavedFeeds([
|
|
2459
|
+
{
|
|
2460
|
+
type: 'feed',
|
|
2461
|
+
value: a,
|
|
2462
|
+
pinned: false,
|
|
2463
|
+
},
|
|
2464
|
+
])
|
|
2465
|
+
const prefs = await agent.getPreferences()
|
|
2466
|
+
expect(prefs.savedFeeds).toStrictEqual([
|
|
2467
|
+
{
|
|
2468
|
+
id: expect.any(String),
|
|
2469
|
+
type: 'timeline',
|
|
2470
|
+
value: 'following',
|
|
2471
|
+
pinned: true,
|
|
2472
|
+
},
|
|
2473
|
+
{
|
|
2474
|
+
id: expect.any(String),
|
|
2475
|
+
type: 'feed',
|
|
2476
|
+
value: a,
|
|
2477
|
+
pinned: false,
|
|
2478
|
+
},
|
|
2479
|
+
])
|
|
2480
|
+
// no v1 prefs to populate from
|
|
2481
|
+
expect(prefs.feeds).toStrictEqual({
|
|
2482
|
+
saved: undefined,
|
|
2483
|
+
pinned: undefined,
|
|
2484
|
+
})
|
|
2485
|
+
})
|
|
2486
|
+
|
|
2487
|
+
it(`existing user with v1 prefs, migrates`, async () => {
|
|
2488
|
+
const one = feedUri()
|
|
2489
|
+
const two = feedUri()
|
|
2490
|
+
await agent.app.bsky.actor.putPreferences({
|
|
2491
|
+
preferences: [
|
|
2492
|
+
{
|
|
2493
|
+
$type: 'app.bsky.actor.defs#savedFeedsPref',
|
|
2494
|
+
pinned: [one],
|
|
2495
|
+
saved: [one, two],
|
|
2496
|
+
},
|
|
2497
|
+
],
|
|
2498
|
+
})
|
|
2499
|
+
const prefs = await agent.getPreferences()
|
|
2500
|
+
|
|
2501
|
+
// deprecated interface receives what it normally would
|
|
2502
|
+
expect(prefs.feeds).toStrictEqual({
|
|
2503
|
+
pinned: [one],
|
|
2504
|
+
saved: [one, two],
|
|
2505
|
+
})
|
|
2506
|
+
// new interface gets new timeline + old pinned feed
|
|
2507
|
+
expect(prefs.savedFeeds).toStrictEqual([
|
|
2508
|
+
{
|
|
2509
|
+
id: expect.any(String),
|
|
2510
|
+
type: 'timeline',
|
|
2511
|
+
value: 'following',
|
|
2512
|
+
pinned: true,
|
|
2513
|
+
},
|
|
2514
|
+
{
|
|
2515
|
+
id: expect.any(String),
|
|
2516
|
+
type: 'feed',
|
|
2517
|
+
value: one,
|
|
2518
|
+
pinned: true,
|
|
2519
|
+
},
|
|
2520
|
+
{
|
|
2521
|
+
id: expect.any(String),
|
|
2522
|
+
type: 'feed',
|
|
2523
|
+
value: two,
|
|
2524
|
+
pinned: false,
|
|
2525
|
+
},
|
|
2526
|
+
])
|
|
2527
|
+
})
|
|
2528
|
+
|
|
2529
|
+
it('squashes duplicates during migration', async () => {
|
|
2530
|
+
const one = feedUri()
|
|
2531
|
+
const two = feedUri()
|
|
2532
|
+
await agent.app.bsky.actor.putPreferences({
|
|
2533
|
+
preferences: [
|
|
2534
|
+
{
|
|
2535
|
+
$type: 'app.bsky.actor.defs#savedFeedsPref',
|
|
2536
|
+
pinned: [one, two],
|
|
2537
|
+
saved: [one, two],
|
|
2538
|
+
},
|
|
2539
|
+
{
|
|
2540
|
+
$type: 'app.bsky.actor.defs#savedFeedsPref',
|
|
2541
|
+
pinned: [],
|
|
2542
|
+
saved: [],
|
|
2543
|
+
},
|
|
2544
|
+
],
|
|
2545
|
+
})
|
|
2546
|
+
|
|
2547
|
+
// performs migration
|
|
2548
|
+
const prefs = await agent.getPreferences()
|
|
2549
|
+
expect(prefs.feeds).toStrictEqual({
|
|
2550
|
+
pinned: [],
|
|
2551
|
+
saved: [],
|
|
2552
|
+
})
|
|
2553
|
+
expect(prefs.savedFeeds).toStrictEqual([
|
|
2554
|
+
{
|
|
2555
|
+
id: expect.any(String),
|
|
2556
|
+
type: 'timeline',
|
|
2557
|
+
value: 'following',
|
|
2558
|
+
pinned: true,
|
|
2559
|
+
},
|
|
2560
|
+
])
|
|
2561
|
+
|
|
2562
|
+
const res = await agent.app.bsky.actor.getPreferences()
|
|
2563
|
+
expect(res.data.preferences).toStrictEqual([
|
|
2564
|
+
{
|
|
2565
|
+
$type: 'app.bsky.actor.defs#savedFeedsPrefV2',
|
|
2566
|
+
items: [
|
|
2567
|
+
{
|
|
2568
|
+
id: expect.any(String),
|
|
2569
|
+
type: 'timeline',
|
|
2570
|
+
value: 'following',
|
|
2571
|
+
pinned: true,
|
|
2572
|
+
},
|
|
2573
|
+
],
|
|
2574
|
+
},
|
|
2575
|
+
{
|
|
2576
|
+
$type: 'app.bsky.actor.defs#savedFeedsPref',
|
|
2577
|
+
pinned: [],
|
|
2578
|
+
saved: [],
|
|
2579
|
+
},
|
|
2580
|
+
])
|
|
2581
|
+
})
|
|
2582
|
+
|
|
2583
|
+
it('v2 writes persist to v1, not the inverse', async () => {
|
|
2584
|
+
const a = feedUri()
|
|
2585
|
+
const b = feedUri()
|
|
2586
|
+
const c = feedUri()
|
|
2587
|
+
const d = feedUri()
|
|
2588
|
+
const e = feedUri()
|
|
2589
|
+
|
|
2590
|
+
await agent.app.bsky.actor.putPreferences({
|
|
2591
|
+
preferences: [
|
|
2592
|
+
{
|
|
2593
|
+
$type: 'app.bsky.actor.defs#savedFeedsPref',
|
|
2594
|
+
pinned: [a, b],
|
|
2595
|
+
saved: [a, b],
|
|
2596
|
+
},
|
|
2597
|
+
],
|
|
2598
|
+
})
|
|
2599
|
+
|
|
2600
|
+
// client updates, migrates to v2
|
|
2601
|
+
// a and b are both pinned
|
|
2602
|
+
await agent.getPreferences()
|
|
2603
|
+
|
|
2604
|
+
// new write to v2, c is saved
|
|
2605
|
+
await agent.addSavedFeeds([
|
|
2606
|
+
{
|
|
2607
|
+
type: 'feed',
|
|
2608
|
+
value: c,
|
|
2609
|
+
pinned: false,
|
|
2610
|
+
},
|
|
2611
|
+
])
|
|
2612
|
+
|
|
2613
|
+
// v2 write wrote to v1 also
|
|
2614
|
+
const res1 = await agent.app.bsky.actor.getPreferences()
|
|
2615
|
+
const v1Pref = res1.data.preferences.find((p) =>
|
|
2616
|
+
AppBskyActorDefs.isSavedFeedsPref(p),
|
|
2617
|
+
)
|
|
2618
|
+
expect(v1Pref).toStrictEqual({
|
|
2619
|
+
$type: 'app.bsky.actor.defs#savedFeedsPref',
|
|
2620
|
+
pinned: [a, b],
|
|
2621
|
+
saved: [a, b, c],
|
|
2622
|
+
})
|
|
2623
|
+
|
|
2624
|
+
// v1 write occurs, d is added but not to v2
|
|
2625
|
+
await agent.addSavedFeed(d)
|
|
2626
|
+
|
|
2627
|
+
const res3 = await agent.app.bsky.actor.getPreferences()
|
|
2628
|
+
const v1Pref3 = res3.data.preferences.find((p) =>
|
|
2629
|
+
AppBskyActorDefs.isSavedFeedsPref(p),
|
|
2630
|
+
)
|
|
2631
|
+
expect(v1Pref3).toStrictEqual({
|
|
2632
|
+
$type: 'app.bsky.actor.defs#savedFeedsPref',
|
|
2633
|
+
pinned: [a, b],
|
|
2634
|
+
saved: [a, b, c, d],
|
|
2635
|
+
})
|
|
2636
|
+
|
|
2637
|
+
// another new write to v2, pins e
|
|
2638
|
+
await agent.addSavedFeeds([
|
|
2639
|
+
{
|
|
2640
|
+
type: 'feed',
|
|
2641
|
+
value: e,
|
|
2642
|
+
pinned: true,
|
|
2643
|
+
},
|
|
2644
|
+
])
|
|
2645
|
+
|
|
2646
|
+
const res4 = await agent.app.bsky.actor.getPreferences()
|
|
2647
|
+
const v1Pref4 = res4.data.preferences.find((p) =>
|
|
2648
|
+
AppBskyActorDefs.isSavedFeedsPref(p),
|
|
2649
|
+
)
|
|
2650
|
+
// v1 pref got v2 write
|
|
2651
|
+
expect(v1Pref4).toStrictEqual({
|
|
2652
|
+
$type: 'app.bsky.actor.defs#savedFeedsPref',
|
|
2653
|
+
pinned: [a, b, e],
|
|
2654
|
+
saved: [a, b, c, d, e],
|
|
2655
|
+
})
|
|
2656
|
+
|
|
2657
|
+
const final = await agent.getPreferences()
|
|
2658
|
+
// d not here bc it was written with v1
|
|
2659
|
+
expect(final.savedFeeds).toStrictEqual([
|
|
2660
|
+
{
|
|
2661
|
+
id: expect.any(String),
|
|
2662
|
+
type: 'timeline',
|
|
2663
|
+
value: 'following',
|
|
2664
|
+
pinned: true,
|
|
2665
|
+
},
|
|
2666
|
+
{ id: expect.any(String), type: 'feed', value: a, pinned: true },
|
|
2667
|
+
{ id: expect.any(String), type: 'feed', value: b, pinned: true },
|
|
2668
|
+
{ id: expect.any(String), type: 'feed', value: e, pinned: true },
|
|
2669
|
+
{ id: expect.any(String), type: 'feed', value: c, pinned: false },
|
|
2670
|
+
])
|
|
2671
|
+
})
|
|
2672
|
+
|
|
2673
|
+
it(`filters out invalid values in v1 prefs`, async () => {
|
|
2674
|
+
// v1 prefs must be valid AtUris, but they could be any type in theory
|
|
2675
|
+
await agent.app.bsky.actor.putPreferences({
|
|
2676
|
+
preferences: [
|
|
2677
|
+
{
|
|
2678
|
+
$type: 'app.bsky.actor.defs#savedFeedsPref',
|
|
2679
|
+
pinned: ['at://did:plc:fake/app.bsky.graph.follow/fake'],
|
|
2680
|
+
saved: ['at://did:plc:fake/app.bsky.graph.follow/fake'],
|
|
2681
|
+
},
|
|
2682
|
+
],
|
|
2683
|
+
})
|
|
2684
|
+
const prefs = await agent.getPreferences()
|
|
2685
|
+
expect(prefs.savedFeeds).toStrictEqual([
|
|
2686
|
+
{
|
|
2687
|
+
id: expect.any(String),
|
|
2688
|
+
type: 'timeline',
|
|
2689
|
+
value: 'following',
|
|
2690
|
+
pinned: true,
|
|
2691
|
+
},
|
|
2692
|
+
])
|
|
2693
|
+
})
|
|
2694
|
+
})
|
|
2695
|
+
|
|
1677
2696
|
// end
|
|
1678
2697
|
})
|
|
1679
2698
|
})
|