@atproto/bsky 0.0.16 → 0.0.18

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 (110) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cache/read-through.d.ts +30 -0
  3. package/dist/config.d.ts +18 -0
  4. package/dist/context.d.ts +6 -6
  5. package/dist/daemon/config.d.ts +15 -0
  6. package/dist/daemon/context.d.ts +15 -0
  7. package/dist/daemon/index.d.ts +23 -0
  8. package/dist/daemon/logger.d.ts +3 -0
  9. package/dist/daemon/notifications.d.ts +18 -0
  10. package/dist/daemon/services.d.ts +11 -0
  11. package/dist/db/database-schema.d.ts +1 -2
  12. package/dist/db/index.js +16 -1
  13. package/dist/db/index.js.map +3 -3
  14. package/dist/db/migrations/20231205T000257238Z-remove-did-cache.d.ts +3 -0
  15. package/dist/db/migrations/index.d.ts +1 -0
  16. package/dist/did-cache.d.ts +10 -7
  17. package/dist/index.d.ts +4 -0
  18. package/dist/index.js +1921 -938
  19. package/dist/index.js.map +3 -3
  20. package/dist/indexer/context.d.ts +2 -0
  21. package/dist/indexer/index.d.ts +1 -0
  22. package/dist/lexicon/index.d.ts +12 -0
  23. package/dist/lexicon/lexicons.d.ts +134 -0
  24. package/dist/lexicon/types/com/atproto/admin/deleteAccount.d.ts +25 -0
  25. package/dist/lexicon/types/com/atproto/temp/importRepo.d.ts +32 -0
  26. package/dist/lexicon/types/com/atproto/temp/pushBlob.d.ts +25 -0
  27. package/dist/lexicon/types/com/atproto/temp/transferAccount.d.ts +42 -0
  28. package/dist/logger.d.ts +1 -0
  29. package/dist/redis.d.ts +10 -1
  30. package/dist/services/actor/index.d.ts +18 -4
  31. package/dist/services/actor/views.d.ts +5 -7
  32. package/dist/services/feed/index.d.ts +6 -4
  33. package/dist/services/feed/views.d.ts +5 -4
  34. package/dist/services/index.d.ts +3 -7
  35. package/dist/services/label/index.d.ts +10 -4
  36. package/dist/services/moderation/index.d.ts +0 -1
  37. package/dist/services/types.d.ts +3 -0
  38. package/dist/services/util/notification.d.ts +5 -0
  39. package/dist/services/util/post.d.ts +6 -6
  40. package/dist/util/retry.d.ts +1 -6
  41. package/package.json +6 -6
  42. package/src/api/app/bsky/actor/searchActorsTypeahead.ts +1 -1
  43. package/src/cache/read-through.ts +151 -0
  44. package/src/config.ts +90 -1
  45. package/src/context.ts +7 -7
  46. package/src/daemon/config.ts +60 -0
  47. package/src/daemon/context.ts +27 -0
  48. package/src/daemon/index.ts +78 -0
  49. package/src/daemon/logger.ts +6 -0
  50. package/src/daemon/notifications.ts +54 -0
  51. package/src/daemon/services.ts +22 -0
  52. package/src/db/database-schema.ts +0 -2
  53. package/src/db/migrations/20231205T000257238Z-remove-did-cache.ts +14 -0
  54. package/src/db/migrations/index.ts +1 -0
  55. package/src/did-cache.ts +33 -56
  56. package/src/feed-gen/index.ts +0 -4
  57. package/src/index.ts +55 -16
  58. package/src/indexer/context.ts +5 -0
  59. package/src/indexer/index.ts +10 -7
  60. package/src/lexicon/index.ts +50 -0
  61. package/src/lexicon/lexicons.ts +156 -0
  62. package/src/lexicon/types/com/atproto/admin/deleteAccount.ts +38 -0
  63. package/src/lexicon/types/com/atproto/temp/importRepo.ts +45 -0
  64. package/src/lexicon/types/com/atproto/temp/pushBlob.ts +39 -0
  65. package/src/lexicon/types/com/atproto/temp/transferAccount.ts +62 -0
  66. package/src/logger.ts +2 -0
  67. package/src/redis.ts +43 -3
  68. package/src/services/actor/index.ts +55 -7
  69. package/src/services/actor/views.ts +16 -13
  70. package/src/services/feed/index.ts +27 -13
  71. package/src/services/feed/views.ts +20 -10
  72. package/src/services/index.ts +14 -14
  73. package/src/services/indexing/index.ts +7 -10
  74. package/src/services/indexing/plugins/post.ts +13 -0
  75. package/src/services/label/index.ts +66 -22
  76. package/src/services/moderation/index.ts +1 -1
  77. package/src/services/moderation/status.ts +1 -4
  78. package/src/services/types.ts +4 -0
  79. package/src/services/util/notification.ts +70 -0
  80. package/src/util/retry.ts +1 -44
  81. package/tests/admin/get-repo.test.ts +5 -3
  82. package/tests/admin/moderation.test.ts +2 -2
  83. package/tests/admin/repo-search.test.ts +1 -0
  84. package/tests/algos/hot-classic.test.ts +1 -2
  85. package/tests/auth.test.ts +1 -1
  86. package/tests/auto-moderator/labeler.test.ts +19 -20
  87. package/tests/auto-moderator/takedowns.test.ts +16 -10
  88. package/tests/blob-resolver.test.ts +4 -2
  89. package/tests/daemon.test.ts +191 -0
  90. package/tests/did-cache.test.ts +20 -5
  91. package/tests/handle-invalidation.test.ts +1 -5
  92. package/tests/indexing.test.ts +20 -13
  93. package/tests/redis-cache.test.ts +231 -0
  94. package/tests/seeds/basic.ts +3 -0
  95. package/tests/subscription/repo.test.ts +4 -7
  96. package/tests/views/profile.test.ts +0 -1
  97. package/tests/views/thread.test.ts +73 -78
  98. package/tests/views/threadgating.test.ts +38 -0
  99. package/dist/db/tables/did-cache.d.ts +0 -10
  100. package/dist/feed-gen/best-of-follows.d.ts +0 -29
  101. package/dist/feed-gen/whats-hot.d.ts +0 -29
  102. package/dist/feed-gen/with-friends.d.ts +0 -3
  103. package/dist/label-cache.d.ts +0 -19
  104. package/src/db/tables/did-cache.ts +0 -13
  105. package/src/feed-gen/best-of-follows.ts +0 -77
  106. package/src/feed-gen/whats-hot.ts +0 -101
  107. package/src/feed-gen/with-friends.ts +0 -43
  108. package/src/label-cache.ts +0 -90
  109. package/tests/algos/whats-hot.test.ts +0 -118
  110. package/tests/algos/with-friends.test.ts +0 -145
@@ -1,90 +0,0 @@
1
- import { wait } from '@atproto/common'
2
- import { PrimaryDatabase } from './db'
3
- import { Label } from './db/tables/label'
4
- import { labelerLogger as log } from './logger'
5
-
6
- export class LabelCache {
7
- bySubject: Record<string, Label[]> = {}
8
- latestLabel = ''
9
- refreshes = 0
10
-
11
- destroyed = false
12
-
13
- constructor(public db: PrimaryDatabase) {}
14
-
15
- start() {
16
- this.poll()
17
- }
18
-
19
- async fullRefresh() {
20
- const allLabels = await this.db.db.selectFrom('label').selectAll().execute()
21
- this.wipeCache()
22
- this.processLabels(allLabels)
23
- }
24
-
25
- async partialRefresh() {
26
- const labels = await this.db.db
27
- .selectFrom('label')
28
- .selectAll()
29
- .where('cts', '>', this.latestLabel)
30
- .execute()
31
- this.processLabels(labels)
32
- }
33
-
34
- async poll() {
35
- try {
36
- if (this.destroyed) return
37
- if (this.refreshes >= 120) {
38
- await this.fullRefresh()
39
- this.refreshes = 0
40
- } else {
41
- await this.partialRefresh()
42
- this.refreshes++
43
- }
44
- } catch (err) {
45
- log.error(
46
- { err, latestLabel: this.latestLabel, refreshes: this.refreshes },
47
- 'label cache failed to refresh',
48
- )
49
- }
50
- await wait(500)
51
- this.poll()
52
- }
53
-
54
- processLabels(labels: Label[]) {
55
- for (const label of labels) {
56
- if (label.cts > this.latestLabel) {
57
- this.latestLabel = label.cts
58
- }
59
- this.bySubject[label.uri] ??= []
60
- this.bySubject[label.uri].push(label)
61
- }
62
- }
63
-
64
- wipeCache() {
65
- this.bySubject = {}
66
- }
67
-
68
- stop() {
69
- this.destroyed = true
70
- }
71
-
72
- forSubject(subject: string, includeNeg = false): Label[] {
73
- const labels = this.bySubject[subject] ?? []
74
- return includeNeg ? labels : labels.filter((l) => l.neg === false)
75
- }
76
-
77
- forSubjects(subjects: string[], includeNeg?: boolean): Label[] {
78
- let labels: Label[] = []
79
- const alreadyAdded = new Set<string>()
80
- for (const subject of subjects) {
81
- if (alreadyAdded.has(subject)) {
82
- continue
83
- }
84
- const subLabels = this.forSubject(subject, includeNeg)
85
- labels = [...labels, ...subLabels]
86
- alreadyAdded.add(subject)
87
- }
88
- return labels
89
- }
90
- }
@@ -1,118 +0,0 @@
1
- import { HOUR } from '@atproto/common'
2
- import AtpAgent, { AtUri } from '@atproto/api'
3
- import { TestNetwork, SeedClient } from '@atproto/dev-env'
4
- import basicSeed from '../seeds/basic'
5
- import { makeAlgos } from '../../src'
6
-
7
- describe.skip('algo whats-hot', () => {
8
- let network: TestNetwork
9
- let agent: AtpAgent
10
- let sc: SeedClient
11
-
12
- // account dids, for convenience
13
- let alice: string
14
- let bob: string
15
- let carol: string
16
-
17
- const feedPublisherDid = 'did:example:feed-publisher'
18
- const feedUri = AtUri.make(
19
- feedPublisherDid,
20
- 'app.bsky.feed.generator',
21
- 'whats-hot',
22
- ).toString()
23
-
24
- beforeAll(async () => {
25
- network = await TestNetwork.create({
26
- dbPostgresSchema: 'bsky_algo_whats_hot',
27
- bsky: { algos: makeAlgos(feedPublisherDid) },
28
- })
29
- agent = new AtpAgent({ service: network.bsky.url })
30
- sc = network.getSeedClient()
31
- await basicSeed(sc)
32
-
33
- alice = sc.dids.alice
34
- bob = sc.dids.bob
35
- carol = sc.dids.carol
36
- await network.processAll()
37
- await network.bsky.processAll()
38
- })
39
-
40
- afterAll(async () => {
41
- await network.close()
42
- })
43
-
44
- it('returns well liked posts', async () => {
45
- const img = await sc.uploadFile(
46
- alice,
47
- 'tests/sample-img/key-landscape-small.jpg',
48
- 'image/jpeg',
49
- )
50
- const one = await sc.post(carol, 'carol is in the chat')
51
- const two = await sc.post(carol, "it's me, carol")
52
- const three = await sc.post(alice, 'first post', undefined, [img])
53
- const four = await sc.post(bob, 'bobby boi')
54
- const five = await sc.post(bob, 'another one')
55
-
56
- for (let i = 0; i < 20; i++) {
57
- const name = `user${i}`
58
- await sc.createAccount(name, {
59
- handle: `user${i}.test`,
60
- email: `user${i}@test.com`,
61
- password: 'password',
62
- })
63
- await sc.like(sc.dids[name], three.ref) // will be down-regulated by time
64
- if (i > 3) {
65
- await sc.like(sc.dids[name], one.ref)
66
- }
67
- if (i > 5) {
68
- await sc.like(sc.dids[name], two.ref)
69
- }
70
- if (i > 7) {
71
- await sc.like(sc.dids[name], four.ref)
72
- await sc.like(sc.dids[name], five.ref)
73
- }
74
- }
75
- await network.bsky.processAll()
76
-
77
- // move the 3rd post 5 hours into the past to check gravity
78
- await network.bsky.ctx.db
79
- .getPrimary()
80
- .db.updateTable('post')
81
- .where('uri', '=', three.ref.uriStr)
82
- .set({ indexedAt: new Date(Date.now() - 5 * HOUR).toISOString() })
83
- .execute()
84
-
85
- await network.bsky.ctx.db
86
- .getPrimary()
87
- .refreshMaterializedView('algo_whats_hot_view')
88
-
89
- const res = await agent.api.app.bsky.feed.getFeed(
90
- { feed: feedUri },
91
- { headers: await network.serviceHeaders(alice) },
92
- )
93
- expect(res.data.feed[0].post.uri).toBe(one.ref.uriStr)
94
- expect(res.data.feed[1].post.uri).toBe(two.ref.uriStr)
95
- const indexOfThird = res.data.feed.findIndex(
96
- (item) => item.post.uri === three.ref.uriStr,
97
- )
98
- // doesn't quite matter where this cam in but it should be down-regulated pretty severely from gravity
99
- expect(indexOfThird).toBeGreaterThan(3)
100
- })
101
-
102
- it('paginates', async () => {
103
- const res = await agent.api.app.bsky.feed.getFeed(
104
- { feed: feedUri },
105
- { headers: await network.serviceHeaders(alice) },
106
- )
107
- const first = await agent.api.app.bsky.feed.getFeed(
108
- { feed: feedUri, limit: 3 },
109
- { headers: await network.serviceHeaders(alice) },
110
- )
111
- const second = await agent.api.app.bsky.feed.getFeed(
112
- { feed: feedUri, cursor: first.data.cursor },
113
- { headers: await network.serviceHeaders(alice) },
114
- )
115
-
116
- expect([...first.data.feed, ...second.data.feed]).toEqual(res.data.feed)
117
- })
118
- })
@@ -1,145 +0,0 @@
1
- import AtpAgent, { AtUri } from '@atproto/api'
2
- import userSeed from '../seeds/users'
3
- import { makeAlgos } from '../../src'
4
- import { TestNetwork, SeedClient, RecordRef } from '@atproto/dev-env'
5
-
6
- describe.skip('algo with friends', () => {
7
- let network: TestNetwork
8
- let agent: AtpAgent
9
- let sc: SeedClient
10
-
11
- // account dids, for convenience
12
- let alice: string
13
- let bob: string
14
- let carol: string
15
- let dan: string
16
-
17
- const feedPublisherDid = 'did:example:feed-publisher'
18
- const feedUri = AtUri.make(
19
- feedPublisherDid,
20
- 'app.bsky.feed.generator',
21
- 'with-friends',
22
- ).toString()
23
-
24
- beforeAll(async () => {
25
- network = await TestNetwork.create({
26
- dbPostgresSchema: 'bsky_algo_with_friends',
27
- bsky: { algos: makeAlgos(feedPublisherDid) },
28
- })
29
- agent = new AtpAgent({ service: network.bsky.url })
30
- sc = network.getSeedClient()
31
- await userSeed(sc)
32
-
33
- alice = sc.dids.alice
34
- bob = sc.dids.bob
35
- carol = sc.dids.carol
36
- dan = sc.dids.dan
37
- await network.processAll()
38
- await network.bsky.processAll()
39
- })
40
-
41
- afterAll(async () => {
42
- await network.close()
43
- })
44
-
45
- let expectedFeed: string[]
46
-
47
- it('setup', async () => {
48
- for (let i = 0; i < 10; i++) {
49
- const name = `user${i}`
50
- await sc.createAccount(name, {
51
- handle: `user${i}.test`,
52
- email: `user${i}@test.com`,
53
- password: 'password',
54
- })
55
- }
56
-
57
- const hitLikeThreshold = async (ref: RecordRef) => {
58
- for (let i = 0; i < 10; i++) {
59
- const name = `user${i}`
60
- await sc.like(sc.dids[name], ref)
61
- }
62
- }
63
-
64
- // bob and dan are mutuals of alice, all userN are out-of-network.
65
- await sc.follow(alice, bob)
66
- await sc.follow(alice, carol)
67
- await sc.follow(alice, dan)
68
- await sc.follow(bob, alice)
69
- await sc.follow(dan, alice)
70
- const one = await sc.post(bob, 'one')
71
- const two = await sc.post(bob, 'two')
72
- const three = await sc.post(carol, 'three')
73
- const four = await sc.post(carol, 'four')
74
- const five = await sc.post(dan, 'five')
75
- const six = await sc.post(dan, 'six')
76
- const seven = await sc.post(sc.dids.user0, 'seven')
77
- const eight = await sc.post(sc.dids.user0, 'eight')
78
- const nine = await sc.post(sc.dids.user1, 'nine')
79
- const ten = await sc.post(sc.dids.user1, 'ten')
80
-
81
- // 1, 2, 3, 4, 6, 8, 10 hit like threshold
82
- await hitLikeThreshold(one.ref)
83
- await hitLikeThreshold(two.ref)
84
- await hitLikeThreshold(three.ref)
85
- await hitLikeThreshold(four.ref)
86
- await hitLikeThreshold(six.ref)
87
- await hitLikeThreshold(eight.ref)
88
- await hitLikeThreshold(ten.ref)
89
-
90
- // 1, 4, 7, 8, 10 liked by mutual
91
- await sc.like(bob, one.ref)
92
- await sc.like(dan, four.ref)
93
- await sc.like(bob, seven.ref)
94
- await sc.like(dan, eight.ref)
95
- await sc.like(bob, nine.ref)
96
- await sc.like(dan, ten.ref)
97
-
98
- // all liked by non-mutual
99
- await sc.like(carol, one.ref)
100
- await sc.like(carol, two.ref)
101
- await sc.like(carol, three.ref)
102
- await sc.like(carol, four.ref)
103
- await sc.like(carol, five.ref)
104
- await sc.like(carol, six.ref)
105
- await sc.like(carol, seven.ref)
106
- await sc.like(carol, eight.ref)
107
- await sc.like(carol, nine.ref)
108
- await sc.like(carol, ten.ref)
109
-
110
- await network.bsky.processAll()
111
-
112
- expectedFeed = [
113
- ten.ref.uriStr,
114
- eight.ref.uriStr,
115
- four.ref.uriStr,
116
- one.ref.uriStr,
117
- ]
118
- })
119
-
120
- it('returns popular in & out of network posts', async () => {
121
- const res = await agent.api.app.bsky.feed.getFeed(
122
- { feed: feedUri },
123
- { headers: await network.serviceHeaders(alice) },
124
- )
125
- const feedUris = res.data.feed.map((i) => i.post.uri)
126
- expect(feedUris).toEqual(expectedFeed)
127
- })
128
-
129
- it('paginates', async () => {
130
- const res = await agent.api.app.bsky.feed.getFeed(
131
- { feed: feedUri },
132
- { headers: await network.serviceHeaders(alice) },
133
- )
134
- const first = await agent.api.app.bsky.feed.getFeed(
135
- { feed: feedUri, limit: 2 },
136
- { headers: await network.serviceHeaders(alice) },
137
- )
138
- const second = await agent.api.app.bsky.feed.getFeed(
139
- { feed: feedUri, cursor: first.data.cursor },
140
- { headers: await network.serviceHeaders(alice) },
141
- )
142
-
143
- expect([...first.data.feed, ...second.data.feed]).toEqual(res.data.feed)
144
- })
145
- })