@atproto/bsky 0.0.76 → 0.0.77
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 +11 -0
- package/dist/api/app/bsky/feed/getActorLikes.js +2 -2
- package/dist/api/app/bsky/feed/getActorLikes.js.map +1 -1
- package/dist/api/app/bsky/feed/getLikes.js +6 -6
- package/dist/api/app/bsky/feed/getLikes.js.map +1 -1
- package/dist/api/app/bsky/feed/getPosts.js +4 -4
- package/dist/api/app/bsky/feed/getPosts.js.map +1 -1
- package/dist/api/app/bsky/feed/getQuotes.d.ts +4 -0
- package/dist/api/app/bsky/feed/getQuotes.d.ts.map +1 -0
- package/dist/api/app/bsky/feed/getQuotes.js +67 -0
- package/dist/api/app/bsky/feed/getQuotes.js.map +1 -0
- package/dist/api/app/bsky/feed/getRepostedBy.js +6 -6
- package/dist/api/app/bsky/feed/getRepostedBy.js.map +1 -1
- package/dist/api/app/bsky/feed/searchPosts.js +4 -4
- package/dist/api/app/bsky/feed/searchPosts.js.map +1 -1
- package/dist/api/app/bsky/graph/getFollowers.js +8 -8
- package/dist/api/app/bsky/graph/getFollowers.js.map +1 -1
- package/dist/api/app/bsky/graph/getList.js +3 -3
- package/dist/api/app/bsky/graph/getList.js.map +1 -1
- package/dist/api/app/bsky/notification/listNotifications.d.ts.map +1 -1
- package/dist/api/app/bsky/notification/listNotifications.js +29 -8
- package/dist/api/app/bsky/notification/listNotifications.js.map +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +2 -0
- package/dist/api/index.js.map +1 -1
- package/dist/data-plane/server/db/database-schema.d.ts +4 -2
- package/dist/data-plane/server/db/database-schema.d.ts.map +1 -1
- package/dist/data-plane/server/db/migrations/20240723T220700077Z-quotes-post-aggs.d.ts +4 -0
- package/dist/data-plane/server/db/migrations/20240723T220700077Z-quotes-post-aggs.d.ts.map +1 -0
- package/dist/data-plane/server/db/migrations/20240723T220700077Z-quotes-post-aggs.js +15 -0
- package/dist/data-plane/server/db/migrations/20240723T220700077Z-quotes-post-aggs.js.map +1 -0
- package/dist/data-plane/server/db/migrations/20240723T220703655Z-quotes.d.ts +4 -0
- package/dist/data-plane/server/db/migrations/20240723T220703655Z-quotes.d.ts.map +1 -0
- package/dist/data-plane/server/db/migrations/20240723T220703655Z-quotes.js +30 -0
- package/dist/data-plane/server/db/migrations/20240723T220703655Z-quotes.js.map +1 -0
- package/dist/data-plane/server/db/migrations/20240801T193939827Z-post-gate.d.ts +4 -0
- package/dist/data-plane/server/db/migrations/20240801T193939827Z-post-gate.d.ts.map +1 -0
- package/dist/data-plane/server/db/migrations/20240801T193939827Z-post-gate.js +20 -0
- package/dist/data-plane/server/db/migrations/20240801T193939827Z-post-gate.js.map +1 -0
- package/dist/data-plane/server/db/migrations/20240808T224251220Z-post-gate-flags.d.ts +4 -0
- package/dist/data-plane/server/db/migrations/20240808T224251220Z-post-gate-flags.d.ts.map +1 -0
- package/dist/data-plane/server/db/migrations/20240808T224251220Z-post-gate-flags.js +28 -0
- package/dist/data-plane/server/db/migrations/20240808T224251220Z-post-gate-flags.js.map +1 -0
- package/dist/data-plane/server/db/migrations/index.d.ts +4 -0
- package/dist/data-plane/server/db/migrations/index.d.ts.map +1 -1
- package/dist/data-plane/server/db/migrations/index.js +5 -1
- package/dist/data-plane/server/db/migrations/index.js.map +1 -1
- package/dist/data-plane/server/db/tables/post-agg.d.ts +1 -0
- package/dist/data-plane/server/db/tables/post-agg.d.ts.map +1 -1
- package/dist/data-plane/server/db/tables/post-gate.d.ts +14 -0
- package/dist/data-plane/server/db/tables/post-gate.d.ts.map +1 -0
- package/dist/data-plane/server/db/tables/post-gate.js +4 -0
- package/dist/data-plane/server/db/tables/post-gate.js.map +1 -0
- package/dist/data-plane/server/db/tables/post.d.ts +3 -0
- package/dist/data-plane/server/db/tables/post.d.ts.map +1 -1
- package/dist/data-plane/server/db/tables/quote.d.ts +16 -0
- package/dist/data-plane/server/db/tables/quote.d.ts.map +1 -0
- package/dist/data-plane/server/db/tables/quote.js +4 -0
- package/dist/data-plane/server/db/tables/quote.js.map +1 -0
- package/dist/data-plane/server/indexing/index.d.ts +2 -0
- package/dist/data-plane/server/indexing/index.d.ts.map +1 -1
- package/dist/data-plane/server/indexing/index.js +6 -0
- package/dist/data-plane/server/indexing/index.js.map +1 -1
- package/dist/data-plane/server/indexing/plugins/post-gate.d.ts +10 -0
- package/dist/data-plane/server/indexing/plugins/post-gate.d.ts.map +1 -0
- package/dist/data-plane/server/indexing/plugins/post-gate.js +101 -0
- package/dist/data-plane/server/indexing/plugins/post-gate.js.map +1 -0
- package/dist/data-plane/server/indexing/plugins/post.d.ts +2 -0
- package/dist/data-plane/server/indexing/plugins/post.d.ts.map +1 -1
- package/dist/data-plane/server/indexing/plugins/post.js +122 -15
- package/dist/data-plane/server/indexing/plugins/post.js.map +1 -1
- package/dist/data-plane/server/indexing/plugins/thread-gate.d.ts.map +1 -1
- package/dist/data-plane/server/indexing/plugins/thread-gate.js +12 -0
- package/dist/data-plane/server/indexing/plugins/thread-gate.js.map +1 -1
- package/dist/data-plane/server/routes/index.d.ts.map +1 -1
- package/dist/data-plane/server/routes/index.js +2 -0
- package/dist/data-plane/server/routes/index.js.map +1 -1
- package/dist/data-plane/server/routes/interactions.d.ts.map +1 -1
- package/dist/data-plane/server/routes/interactions.js +2 -1
- package/dist/data-plane/server/routes/interactions.js.map +1 -1
- package/dist/data-plane/server/routes/quotes.d.ts +6 -0
- package/dist/data-plane/server/routes/quotes.d.ts.map +1 -0
- package/dist/data-plane/server/routes/quotes.js +27 -0
- package/dist/data-plane/server/routes/quotes.js.map +1 -0
- package/dist/data-plane/server/routes/records.d.ts.map +1 -1
- package/dist/data-plane/server/routes/records.js +11 -1
- package/dist/data-plane/server/routes/records.js.map +1 -1
- package/dist/data-plane/server/util.d.ts +6 -7
- package/dist/data-plane/server/util.d.ts.map +1 -1
- package/dist/data-plane/server/util.js +1 -9
- package/dist/data-plane/server/util.js.map +1 -1
- package/dist/hydration/feed.d.ts +10 -0
- package/dist/hydration/feed.d.ts.map +1 -1
- package/dist/hydration/feed.js +31 -7
- package/dist/hydration/feed.js.map +1 -1
- package/dist/hydration/hydrator.d.ts +4 -2
- package/dist/hydration/hydrator.d.ts.map +1 -1
- package/dist/hydration/hydrator.js +89 -34
- package/dist/hydration/hydrator.js.map +1 -1
- package/dist/hydration/util.d.ts +0 -1
- package/dist/hydration/util.d.ts.map +1 -1
- package/dist/hydration/util.js +1 -5
- package/dist/hydration/util.js.map +1 -1
- package/dist/lexicon/index.d.ts +2 -0
- package/dist/lexicon/index.d.ts.map +1 -1
- package/dist/lexicon/index.js +4 -0
- package/dist/lexicon/index.js.map +1 -1
- package/dist/lexicon/lexicons.d.ts +141 -0
- package/dist/lexicon/lexicons.d.ts.map +1 -1
- package/dist/lexicon/lexicons.js +142 -0
- package/dist/lexicon/lexicons.js.map +1 -1
- package/dist/lexicon/types/app/bsky/embed/record.d.ts +8 -1
- package/dist/lexicon/types/app/bsky/embed/record.d.ts.map +1 -1
- package/dist/lexicon/types/app/bsky/embed/record.js +11 -1
- package/dist/lexicon/types/app/bsky/embed/record.js.map +1 -1
- package/dist/lexicon/types/app/bsky/feed/defs.d.ts +2 -0
- package/dist/lexicon/types/app/bsky/feed/defs.d.ts.map +1 -1
- package/dist/lexicon/types/app/bsky/feed/defs.js.map +1 -1
- package/dist/lexicon/types/app/bsky/feed/getQuotes.d.ts +44 -0
- package/dist/lexicon/types/app/bsky/feed/getQuotes.d.ts.map +1 -0
- package/dist/lexicon/types/app/bsky/feed/getQuotes.js +3 -0
- package/dist/lexicon/types/app/bsky/feed/getQuotes.js.map +1 -0
- package/dist/lexicon/types/app/bsky/feed/postgate.d.ts +25 -0
- package/dist/lexicon/types/app/bsky/feed/postgate.d.ts.map +1 -0
- package/dist/lexicon/types/app/bsky/feed/postgate.js +27 -0
- package/dist/lexicon/types/app/bsky/feed/postgate.js.map +1 -0
- package/dist/lexicon/types/app/bsky/feed/threadgate.d.ts +2 -0
- package/dist/lexicon/types/app/bsky/feed/threadgate.d.ts.map +1 -1
- package/dist/lexicon/types/app/bsky/feed/threadgate.js.map +1 -1
- package/dist/proto/bsky_connect.d.ts +21 -1
- package/dist/proto/bsky_connect.d.ts.map +1 -1
- package/dist/proto/bsky_connect.js +20 -0
- package/dist/proto/bsky_connect.js.map +1 -1
- package/dist/proto/bsky_pb.d.ts +96 -0
- package/dist/proto/bsky_pb.d.ts.map +1 -1
- package/dist/proto/bsky_pb.js +306 -4
- package/dist/proto/bsky_pb.js.map +1 -1
- package/dist/util/uris.d.ts +12 -0
- package/dist/util/uris.d.ts.map +1 -0
- package/dist/util/uris.js +34 -0
- package/dist/util/uris.js.map +1 -0
- package/dist/views/index.d.ts +8 -2
- package/dist/views/index.d.ts.map +1 -1
- package/dist/views/index.js +83 -39
- package/dist/views/index.js.map +1 -1
- package/dist/views/types.d.ts +1 -1
- package/dist/views/types.d.ts.map +1 -1
- package/dist/views/types.js.map +1 -1
- package/dist/views/util.d.ts +11 -1
- package/dist/views/util.d.ts.map +1 -1
- package/dist/views/util.js +19 -8
- package/dist/views/util.js.map +1 -1
- package/package.json +4 -4
- package/proto/bsky.proto +33 -0
- package/src/api/app/bsky/feed/getActorLikes.ts +1 -1
- package/src/api/app/bsky/feed/getLikes.ts +1 -1
- package/src/api/app/bsky/feed/getPosts.ts +1 -1
- package/src/api/app/bsky/feed/getQuotes.ts +105 -0
- package/src/api/app/bsky/feed/getRepostedBy.ts +1 -1
- package/src/api/app/bsky/feed/searchPosts.ts +1 -1
- package/src/api/app/bsky/graph/getFollowers.ts +1 -1
- package/src/api/app/bsky/graph/getList.ts +1 -1
- package/src/api/app/bsky/notification/listNotifications.ts +32 -6
- package/src/api/index.ts +2 -0
- package/src/data-plane/server/db/database-schema.ts +7 -3
- package/src/data-plane/server/db/migrations/20240723T220700077Z-quotes-post-aggs.ts +12 -0
- package/src/data-plane/server/db/migrations/20240723T220703655Z-quotes.ts +28 -0
- package/src/data-plane/server/db/migrations/20240801T193939827Z-post-gate.ts +17 -0
- package/src/data-plane/server/db/migrations/20240808T224251220Z-post-gate-flags.ts +25 -0
- package/src/data-plane/server/db/migrations/index.ts +4 -0
- package/src/data-plane/server/db/tables/post-agg.ts +1 -0
- package/src/data-plane/server/db/tables/post-gate.ts +12 -0
- package/src/data-plane/server/db/tables/post.ts +3 -0
- package/src/data-plane/server/db/tables/quote.ts +15 -0
- package/src/data-plane/server/indexing/index.ts +7 -0
- package/src/data-plane/server/indexing/plugins/post-gate.ts +104 -0
- package/src/data-plane/server/indexing/plugins/post.ts +151 -16
- package/src/data-plane/server/indexing/plugins/thread-gate.ts +12 -0
- package/src/data-plane/server/routes/index.ts +2 -0
- package/src/data-plane/server/routes/interactions.ts +2 -1
- package/src/data-plane/server/routes/quotes.ts +32 -0
- package/src/data-plane/server/routes/records.ts +11 -1
- package/src/data-plane/server/util.ts +0 -8
- package/src/hydration/feed.ts +58 -12
- package/src/hydration/hydrator.ts +94 -22
- package/src/hydration/util.ts +0 -4
- package/src/lexicon/index.ts +12 -0
- package/src/lexicon/lexicons.ts +145 -0
- package/src/lexicon/types/app/bsky/embed/record.ts +19 -0
- package/src/lexicon/types/app/bsky/feed/defs.ts +2 -0
- package/src/lexicon/types/app/bsky/feed/getQuotes.ts +54 -0
- package/src/lexicon/types/app/bsky/feed/postgate.ts +47 -0
- package/src/lexicon/types/app/bsky/feed/threadgate.ts +2 -0
- package/src/proto/bsky_connect.ts +24 -0
- package/src/proto/bsky_pb.ts +289 -0
- package/src/util/uris.ts +31 -0
- package/src/views/index.ts +90 -35
- package/src/views/types.ts +1 -0
- package/src/views/util.ts +37 -7
- package/tests/__snapshots__/feed-generation.test.ts.snap +37 -0
- package/tests/data-plane/__snapshots__/indexing.test.ts.snap +18 -0
- package/tests/data-plane/indexing.test.ts +1 -0
- package/tests/postgates.test.ts +186 -0
- package/tests/seed/feed-hidden-replies.ts +62 -0
- package/tests/seed/postgates.ts +56 -0
- package/tests/views/__snapshots__/author-feed.test.ts.snap +56 -0
- package/tests/views/__snapshots__/block-lists.test.ts.snap +6 -0
- package/tests/views/__snapshots__/blocks.test.ts.snap +10 -0
- package/tests/views/__snapshots__/list-feed.test.ts.snap +22 -0
- package/tests/views/__snapshots__/mute-lists.test.ts.snap +8 -0
- package/tests/views/__snapshots__/mutes.test.ts.snap +6 -0
- package/tests/views/__snapshots__/posts.test.ts.snap +12 -0
- package/tests/views/__snapshots__/quotes.test.ts.snap +399 -0
- package/tests/views/__snapshots__/thread.test.ts.snap +50 -0
- package/tests/views/__snapshots__/timeline.test.ts.snap +170 -0
- package/tests/views/author-feed.test.ts +3 -9
- package/tests/views/feed-hidden-replies.test.ts +246 -0
- package/tests/views/feed-view-post.test.ts +501 -0
- package/tests/views/quotes.test.ts +105 -0
|
@@ -17,6 +17,7 @@ import { Database } from '../db'
|
|
|
17
17
|
import { Actor } from '../db/tables/actor'
|
|
18
18
|
import * as Post from './plugins/post'
|
|
19
19
|
import * as Threadgate from './plugins/thread-gate'
|
|
20
|
+
import * as Postgate from './plugins/post-gate'
|
|
20
21
|
import * as Like from './plugins/like'
|
|
21
22
|
import * as Repost from './plugins/repost'
|
|
22
23
|
import * as Follow from './plugins/follow'
|
|
@@ -38,6 +39,7 @@ export class IndexingService {
|
|
|
38
39
|
records: {
|
|
39
40
|
post: Post.PluginType
|
|
40
41
|
threadGate: Threadgate.PluginType
|
|
42
|
+
postGate: Postgate.PluginType
|
|
41
43
|
like: Like.PluginType
|
|
42
44
|
repost: Repost.PluginType
|
|
43
45
|
follow: Follow.PluginType
|
|
@@ -60,6 +62,7 @@ export class IndexingService {
|
|
|
60
62
|
this.records = {
|
|
61
63
|
post: Post.makePlugin(this.db, this.background),
|
|
62
64
|
threadGate: Threadgate.makePlugin(this.db, this.background),
|
|
65
|
+
postGate: Postgate.makePlugin(this.db, this.background),
|
|
63
66
|
like: Like.makePlugin(this.db, this.background),
|
|
64
67
|
repost: Repost.makePlugin(this.db, this.background),
|
|
65
68
|
follow: Follow.makePlugin(this.db, this.background),
|
|
@@ -365,6 +368,10 @@ export class IndexingService {
|
|
|
365
368
|
.deleteFrom('thread_gate')
|
|
366
369
|
.where('creator', '=', did)
|
|
367
370
|
.execute()
|
|
371
|
+
await this.db.db
|
|
372
|
+
.deleteFrom('post_gate')
|
|
373
|
+
.where('creator', '=', did)
|
|
374
|
+
.execute()
|
|
368
375
|
// notifications
|
|
369
376
|
await this.db.db
|
|
370
377
|
.deleteFrom('notification')
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { AtUri, normalizeDatetimeAlways } from '@atproto/syntax'
|
|
2
|
+
import { InvalidRequestError } from '@atproto/xrpc-server'
|
|
3
|
+
import { CID } from 'multiformats/cid'
|
|
4
|
+
import * as Postgate from '../../../../lexicon/types/app/bsky/feed/postgate'
|
|
5
|
+
import * as lex from '../../../../lexicon/lexicons'
|
|
6
|
+
import { DatabaseSchema, DatabaseSchemaType } from '../../db/database-schema'
|
|
7
|
+
import { Database } from '../../db'
|
|
8
|
+
import RecordProcessor from '../processor'
|
|
9
|
+
import { BackgroundQueue } from '../../background'
|
|
10
|
+
|
|
11
|
+
const lexId = lex.ids.AppBskyFeedPostgate
|
|
12
|
+
type IndexedGate = DatabaseSchemaType['post_gate']
|
|
13
|
+
|
|
14
|
+
const insertFn = async (
|
|
15
|
+
db: DatabaseSchema,
|
|
16
|
+
uri: AtUri,
|
|
17
|
+
cid: CID,
|
|
18
|
+
obj: Postgate.Record,
|
|
19
|
+
timestamp: string,
|
|
20
|
+
): Promise<IndexedGate | null> => {
|
|
21
|
+
const postUri = new AtUri(obj.post)
|
|
22
|
+
if (postUri.host !== uri.host || postUri.rkey !== uri.rkey) {
|
|
23
|
+
throw new InvalidRequestError(
|
|
24
|
+
'Creator and rkey of post gate does not match its post',
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
const inserted = await db
|
|
28
|
+
.insertInto('post_gate')
|
|
29
|
+
.values({
|
|
30
|
+
uri: uri.toString(),
|
|
31
|
+
cid: cid.toString(),
|
|
32
|
+
creator: uri.host,
|
|
33
|
+
postUri: obj.post,
|
|
34
|
+
createdAt: normalizeDatetimeAlways(obj.createdAt),
|
|
35
|
+
indexedAt: timestamp,
|
|
36
|
+
})
|
|
37
|
+
.onConflict((oc) => oc.doNothing())
|
|
38
|
+
.returningAll()
|
|
39
|
+
.executeTakeFirst()
|
|
40
|
+
await db
|
|
41
|
+
.updateTable('post')
|
|
42
|
+
.where('uri', '=', postUri.toString())
|
|
43
|
+
.set({ hasPostGate: true })
|
|
44
|
+
.executeTakeFirst()
|
|
45
|
+
return inserted || null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const findDuplicate = async (
|
|
49
|
+
db: DatabaseSchema,
|
|
50
|
+
_uri: AtUri,
|
|
51
|
+
obj: Postgate.Record,
|
|
52
|
+
): Promise<AtUri | null> => {
|
|
53
|
+
const found = await db
|
|
54
|
+
.selectFrom('post_gate')
|
|
55
|
+
.where('postUri', '=', obj.post)
|
|
56
|
+
.selectAll()
|
|
57
|
+
.executeTakeFirst()
|
|
58
|
+
return found ? new AtUri(found.uri) : null
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const notifsForInsert = () => {
|
|
62
|
+
return []
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const deleteFn = async (
|
|
66
|
+
db: DatabaseSchema,
|
|
67
|
+
uri: AtUri,
|
|
68
|
+
): Promise<IndexedGate | null> => {
|
|
69
|
+
const deleted = await db
|
|
70
|
+
.deleteFrom('post_gate')
|
|
71
|
+
.where('uri', '=', uri.toString())
|
|
72
|
+
.returningAll()
|
|
73
|
+
.executeTakeFirst()
|
|
74
|
+
if (deleted) {
|
|
75
|
+
await db
|
|
76
|
+
.updateTable('post')
|
|
77
|
+
.where('uri', '=', deleted.postUri)
|
|
78
|
+
.set({ hasPostGate: false })
|
|
79
|
+
.executeTakeFirst()
|
|
80
|
+
}
|
|
81
|
+
return deleted || null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const notifsForDelete = () => {
|
|
85
|
+
return { notifs: [], toDelete: [] }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type PluginType = RecordProcessor<Postgate.Record, IndexedGate>
|
|
89
|
+
|
|
90
|
+
export const makePlugin = (
|
|
91
|
+
db: Database,
|
|
92
|
+
background: BackgroundQueue,
|
|
93
|
+
): PluginType => {
|
|
94
|
+
return new RecordProcessor(db, background, {
|
|
95
|
+
lexId,
|
|
96
|
+
insertFn,
|
|
97
|
+
findDuplicate,
|
|
98
|
+
deleteFn,
|
|
99
|
+
notifsForInsert,
|
|
100
|
+
notifsForDelete,
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export default makePlugin
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
ReplyRef,
|
|
8
8
|
} from '../../../../lexicon/types/app/bsky/feed/post'
|
|
9
9
|
import { Record as GateRecord } from '../../../../lexicon/types/app/bsky/feed/threadgate'
|
|
10
|
+
import { Record as PostgateRecord } from '../../../../lexicon/types/app/bsky/feed/postgate'
|
|
10
11
|
import { isMain as isEmbedImage } from '../../../../lexicon/types/app/bsky/embed/images'
|
|
11
12
|
import { isMain as isEmbedExternal } from '../../../../lexicon/types/app/bsky/embed/external'
|
|
12
13
|
import { isMain as isEmbedRecord } from '../../../../lexicon/types/app/bsky/embed/record'
|
|
@@ -26,9 +27,14 @@ import {
|
|
|
26
27
|
getDescendentsQb,
|
|
27
28
|
invalidReplyRoot as checkInvalidReplyRoot,
|
|
28
29
|
violatesThreadGate as checkViolatesThreadGate,
|
|
29
|
-
postToThreadgateUri,
|
|
30
30
|
} from '../../util'
|
|
31
31
|
import { BackgroundQueue } from '../../background'
|
|
32
|
+
import { parsePostgate } from '../../../../views/util'
|
|
33
|
+
import {
|
|
34
|
+
postUriToThreadgateUri,
|
|
35
|
+
postUriToPostgateUri,
|
|
36
|
+
uriToDid,
|
|
37
|
+
} from '../../../../util/uris'
|
|
32
38
|
|
|
33
39
|
type Notif = Insertable<Notification>
|
|
34
40
|
type Post = Selectable<DatabaseSchemaType['post']>
|
|
@@ -52,6 +58,7 @@ type IndexedPost = {
|
|
|
52
58
|
embeds?: (PostEmbedImage[] | PostEmbedExternal | PostEmbedRecord)[]
|
|
53
59
|
ancestors?: PostAncestor[]
|
|
54
60
|
descendents?: PostDescendent[]
|
|
61
|
+
threadgate?: GateRecord
|
|
55
62
|
}
|
|
56
63
|
|
|
57
64
|
const lexId = lex.ids.AppBskyFeedPost
|
|
@@ -168,6 +175,7 @@ const insertFn = async (
|
|
|
168
175
|
await db.insertInto('post_embed_external').values(externalEmbed).execute()
|
|
169
176
|
} else if (isEmbedRecord(postEmbed)) {
|
|
170
177
|
const { record } = postEmbed
|
|
178
|
+
const embedUri = new AtUri(record.uri)
|
|
171
179
|
const recordEmbed = {
|
|
172
180
|
postUri: uri.toString(),
|
|
173
181
|
embedUri: record.uri,
|
|
@@ -175,9 +183,59 @@ const insertFn = async (
|
|
|
175
183
|
}
|
|
176
184
|
embeds.push(recordEmbed)
|
|
177
185
|
await db.insertInto('post_embed_record').values(recordEmbed).execute()
|
|
186
|
+
|
|
187
|
+
if (embedUri.collection === lex.ids.AppBskyFeedPost) {
|
|
188
|
+
const quote = {
|
|
189
|
+
uri: uri.toString(),
|
|
190
|
+
cid: cid.toString(),
|
|
191
|
+
subject: record.uri,
|
|
192
|
+
subjectCid: record.cid,
|
|
193
|
+
createdAt: normalizeDatetimeAlways(obj.createdAt),
|
|
194
|
+
indexedAt: timestamp,
|
|
195
|
+
}
|
|
196
|
+
await db
|
|
197
|
+
.insertInto('quote')
|
|
198
|
+
.values(quote)
|
|
199
|
+
.onConflict((oc) => oc.doNothing())
|
|
200
|
+
.returningAll()
|
|
201
|
+
.executeTakeFirst()
|
|
202
|
+
|
|
203
|
+
const quoteCountQb = db
|
|
204
|
+
.insertInto('post_agg')
|
|
205
|
+
.values({
|
|
206
|
+
uri: record.uri.toString(),
|
|
207
|
+
quoteCount: db
|
|
208
|
+
.selectFrom('quote')
|
|
209
|
+
.where('quote.subjectCid', '=', record.cid.toString())
|
|
210
|
+
.select(countAll.as('count')),
|
|
211
|
+
})
|
|
212
|
+
.onConflict((oc) =>
|
|
213
|
+
oc
|
|
214
|
+
.column('uri')
|
|
215
|
+
.doUpdateSet({ quoteCount: excluded(db, 'quoteCount') }),
|
|
216
|
+
)
|
|
217
|
+
await quoteCountQb.execute()
|
|
218
|
+
|
|
219
|
+
const { violatesEmbeddingRules } = await validatePostEmbed(
|
|
220
|
+
db,
|
|
221
|
+
embedUri.toString(),
|
|
222
|
+
uri.toString(),
|
|
223
|
+
)
|
|
224
|
+
Object.assign(insertedPost, {
|
|
225
|
+
violatesEmbeddingRules: violatesEmbeddingRules,
|
|
226
|
+
})
|
|
227
|
+
if (violatesEmbeddingRules) {
|
|
228
|
+
await db
|
|
229
|
+
.updateTable('post')
|
|
230
|
+
.where('uri', '=', insertedPost.uri)
|
|
231
|
+
.set({ violatesEmbeddingRules: violatesEmbeddingRules })
|
|
232
|
+
.executeTakeFirst()
|
|
233
|
+
}
|
|
234
|
+
}
|
|
178
235
|
}
|
|
179
236
|
}
|
|
180
237
|
|
|
238
|
+
const threadgate = await getThreadgateRecord(db, post.replyRoot || post.uri)
|
|
181
239
|
const ancestors = await getAncestorsAndSelfQb(db, {
|
|
182
240
|
uri: post.uri,
|
|
183
241
|
parentHeight: REPLY_NOTIF_DEPTH,
|
|
@@ -200,6 +258,7 @@ const insertFn = async (
|
|
|
200
258
|
embeds,
|
|
201
259
|
ancestors,
|
|
202
260
|
descendents,
|
|
261
|
+
threadgate,
|
|
203
262
|
}
|
|
204
263
|
}
|
|
205
264
|
|
|
@@ -228,19 +287,22 @@ const notifsForInsert = (obj: IndexedPost) => {
|
|
|
228
287
|
})
|
|
229
288
|
}
|
|
230
289
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if (embedUri
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
290
|
+
|
|
291
|
+
if (!obj.post.violatesEmbeddingRules) {
|
|
292
|
+
for (const embed of obj.embeds ?? []) {
|
|
293
|
+
if ('embedUri' in embed) {
|
|
294
|
+
const embedUri = new AtUri(embed.embedUri)
|
|
295
|
+
if (embedUri.collection === lex.ids.AppBskyFeedPost) {
|
|
296
|
+
maybeNotify({
|
|
297
|
+
did: embedUri.host,
|
|
298
|
+
reason: 'quote',
|
|
299
|
+
reasonSubject: embedUri.toString(),
|
|
300
|
+
author: obj.post.creator,
|
|
301
|
+
recordUri: obj.post.uri,
|
|
302
|
+
recordCid: obj.post.cid,
|
|
303
|
+
sortAt: obj.post.sortAt,
|
|
304
|
+
})
|
|
305
|
+
}
|
|
244
306
|
}
|
|
245
307
|
}
|
|
246
308
|
}
|
|
@@ -250,6 +312,8 @@ const notifsForInsert = (obj: IndexedPost) => {
|
|
|
250
312
|
return notifs
|
|
251
313
|
}
|
|
252
314
|
|
|
315
|
+
const threadgateHiddenReplies = obj.threadgate?.hiddenReplies || []
|
|
316
|
+
|
|
253
317
|
// reply notifications
|
|
254
318
|
|
|
255
319
|
for (const ancestor of obj.ancestors ?? []) {
|
|
@@ -265,6 +329,8 @@ const notifsForInsert = (obj: IndexedPost) => {
|
|
|
265
329
|
recordCid: obj.post.cid,
|
|
266
330
|
sortAt: obj.post.sortAt,
|
|
267
331
|
})
|
|
332
|
+
// found hidden reply, don't notify any higher ancestors
|
|
333
|
+
if (threadgateHiddenReplies.includes(ancestorUri.toString())) break
|
|
268
334
|
}
|
|
269
335
|
}
|
|
270
336
|
|
|
@@ -304,6 +370,7 @@ const deleteFn = async (
|
|
|
304
370
|
.executeTakeFirst(),
|
|
305
371
|
db.deleteFrom('feed_item').where('postUri', '=', uriStr).executeTakeFirst(),
|
|
306
372
|
])
|
|
373
|
+
await db.deleteFrom('quote').where('subject', '=', uriStr).execute()
|
|
307
374
|
const deletedEmbeds: (
|
|
308
375
|
| PostEmbedImage[]
|
|
309
376
|
| PostEmbedExternal
|
|
@@ -333,7 +400,27 @@ const deleteFn = async (
|
|
|
333
400
|
deletedEmbeds.push(deletedExternals)
|
|
334
401
|
}
|
|
335
402
|
if (deletedPosts) {
|
|
403
|
+
const embedUri = new AtUri(deletedPosts.embedUri)
|
|
336
404
|
deletedEmbeds.push(deletedPosts)
|
|
405
|
+
|
|
406
|
+
if (embedUri.collection === lex.ids.AppBskyFeedPost) {
|
|
407
|
+
await db.deleteFrom('quote').where('uri', '=', uriStr).execute()
|
|
408
|
+
await db
|
|
409
|
+
.insertInto('post_agg')
|
|
410
|
+
.values({
|
|
411
|
+
uri: deletedPosts.embedUri,
|
|
412
|
+
quoteCount: db
|
|
413
|
+
.selectFrom('quote')
|
|
414
|
+
.where('quote.subjectCid', '=', deletedPosts.embedCid.toString())
|
|
415
|
+
.select(countAll.as('count')),
|
|
416
|
+
})
|
|
417
|
+
.onConflict((oc) =>
|
|
418
|
+
oc
|
|
419
|
+
.column('uri')
|
|
420
|
+
.doUpdateSet({ quoteCount: excluded(db, 'quoteCount') }),
|
|
421
|
+
)
|
|
422
|
+
.execute()
|
|
423
|
+
}
|
|
337
424
|
}
|
|
338
425
|
return deleted
|
|
339
426
|
? {
|
|
@@ -434,7 +521,7 @@ async function validateReply(
|
|
|
434
521
|
const violatesThreadGate = await checkViolatesThreadGate(
|
|
435
522
|
db,
|
|
436
523
|
creator,
|
|
437
|
-
|
|
524
|
+
uriToDid(reply.root.uri),
|
|
438
525
|
replyRefs.root?.record ?? null,
|
|
439
526
|
replyRefs.gate?.record ?? null,
|
|
440
527
|
)
|
|
@@ -444,10 +531,58 @@ async function validateReply(
|
|
|
444
531
|
}
|
|
445
532
|
}
|
|
446
533
|
|
|
534
|
+
async function getThreadgateRecord(db: DatabaseSchema, postUri: string) {
|
|
535
|
+
const threadgateRecordUri = postUriToThreadgateUri(postUri)
|
|
536
|
+
const results = await db
|
|
537
|
+
.selectFrom('record')
|
|
538
|
+
.where('record.uri', '=', threadgateRecordUri)
|
|
539
|
+
.selectAll()
|
|
540
|
+
.execute()
|
|
541
|
+
const threadgateRecord = results.find(
|
|
542
|
+
(ref) => ref.uri === threadgateRecordUri,
|
|
543
|
+
)
|
|
544
|
+
if (threadgateRecord) {
|
|
545
|
+
return jsonStringToLex(threadgateRecord.json) as GateRecord
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
async function validatePostEmbed(
|
|
550
|
+
db: DatabaseSchema,
|
|
551
|
+
embedUri: string,
|
|
552
|
+
parentUri: string,
|
|
553
|
+
) {
|
|
554
|
+
const postgateRecordUri = postUriToPostgateUri(embedUri)
|
|
555
|
+
const postgateRecord = await db
|
|
556
|
+
.selectFrom('record')
|
|
557
|
+
.where('record.uri', '=', postgateRecordUri)
|
|
558
|
+
.selectAll()
|
|
559
|
+
.executeTakeFirst()
|
|
560
|
+
if (!postgateRecord) {
|
|
561
|
+
return {
|
|
562
|
+
violatesEmbeddingRules: false,
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
const {
|
|
566
|
+
embeddingRules: { canEmbed },
|
|
567
|
+
} = parsePostgate({
|
|
568
|
+
gate: jsonStringToLex(postgateRecord.json) as PostgateRecord,
|
|
569
|
+
viewerDid: uriToDid(parentUri),
|
|
570
|
+
authorDid: uriToDid(embedUri),
|
|
571
|
+
})
|
|
572
|
+
if (canEmbed) {
|
|
573
|
+
return {
|
|
574
|
+
violatesEmbeddingRules: false,
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return {
|
|
578
|
+
violatesEmbeddingRules: true,
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
447
582
|
async function getReplyRefs(db: DatabaseSchema, reply: ReplyRef) {
|
|
448
583
|
const replyRoot = reply.root.uri
|
|
449
584
|
const replyParent = reply.parent.uri
|
|
450
|
-
const replyGate =
|
|
585
|
+
const replyGate = postUriToThreadgateUri(replyRoot)
|
|
451
586
|
const results = await db
|
|
452
587
|
.selectFrom('record')
|
|
453
588
|
.where('record.uri', 'in', [replyRoot, replyGate, replyParent])
|
|
@@ -37,6 +37,11 @@ const insertFn = async (
|
|
|
37
37
|
.onConflict((oc) => oc.doNothing())
|
|
38
38
|
.returningAll()
|
|
39
39
|
.executeTakeFirst()
|
|
40
|
+
await db
|
|
41
|
+
.updateTable('post')
|
|
42
|
+
.where('uri', '=', postUri.toString())
|
|
43
|
+
.set({ hasThreadGate: true })
|
|
44
|
+
.executeTakeFirst()
|
|
40
45
|
return inserted || null
|
|
41
46
|
}
|
|
42
47
|
|
|
@@ -66,6 +71,13 @@ const deleteFn = async (
|
|
|
66
71
|
.where('uri', '=', uri.toString())
|
|
67
72
|
.returningAll()
|
|
68
73
|
.executeTakeFirst()
|
|
74
|
+
if (deleted) {
|
|
75
|
+
await db
|
|
76
|
+
.updateTable('post')
|
|
77
|
+
.where('uri', '=', deleted.postUri)
|
|
78
|
+
.set({ hasThreadGate: false })
|
|
79
|
+
.executeTakeFirst()
|
|
80
|
+
}
|
|
69
81
|
return deleted || null
|
|
70
82
|
}
|
|
71
83
|
|
|
@@ -15,6 +15,7 @@ import mutes from './mutes'
|
|
|
15
15
|
import notifs from './notifs'
|
|
16
16
|
import posts from './posts'
|
|
17
17
|
import profile from './profile'
|
|
18
|
+
import quotes from './quotes'
|
|
18
19
|
import records from './records'
|
|
19
20
|
import relationships from './relationships'
|
|
20
21
|
import reposts from './reposts'
|
|
@@ -42,6 +43,7 @@ export default (db: Database, idResolver: IdResolver) =>
|
|
|
42
43
|
...notifs(db),
|
|
43
44
|
...posts(db),
|
|
44
45
|
...profile(db),
|
|
46
|
+
...quotes(db),
|
|
45
47
|
...records(db),
|
|
46
48
|
...relationships(db),
|
|
47
49
|
...reposts(db),
|
|
@@ -8,7 +8,7 @@ export default (db: Database): Partial<ServiceImpl<typeof Service>> => ({
|
|
|
8
8
|
async getInteractionCounts(req) {
|
|
9
9
|
const uris = req.refs.map((ref) => ref.uri)
|
|
10
10
|
if (uris.length === 0) {
|
|
11
|
-
return { likes: [], replies: [], reposts: [] }
|
|
11
|
+
return { likes: [], replies: [], reposts: [], quotes: [] }
|
|
12
12
|
}
|
|
13
13
|
const res = await db.db
|
|
14
14
|
.selectFrom('post_agg')
|
|
@@ -20,6 +20,7 @@ export default (db: Database): Partial<ServiceImpl<typeof Service>> => ({
|
|
|
20
20
|
likes: uris.map((uri) => byUri[uri]?.likeCount ?? 0),
|
|
21
21
|
replies: uris.map((uri) => byUri[uri]?.replyCount ?? 0),
|
|
22
22
|
reposts: uris.map((uri) => byUri[uri]?.repostCount ?? 0),
|
|
23
|
+
quotes: uris.map((uri) => byUri[uri]?.quoteCount ?? 0),
|
|
23
24
|
}
|
|
24
25
|
},
|
|
25
26
|
async getCountsForUsers(req) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ServiceImpl } from '@connectrpc/connect'
|
|
2
|
+
import { Service } from '../../../proto/bsky_connect'
|
|
3
|
+
import { Database } from '../db'
|
|
4
|
+
import { paginate, TimeCidKeyset } from '../db/pagination'
|
|
5
|
+
|
|
6
|
+
export default (db: Database): Partial<ServiceImpl<typeof Service>> => ({
|
|
7
|
+
async getQuotesBySubject(req) {
|
|
8
|
+
const { subject, cursor, limit } = req
|
|
9
|
+
const { ref } = db.db.dynamic
|
|
10
|
+
|
|
11
|
+
if (!subject?.uri) return { uris: [] }
|
|
12
|
+
|
|
13
|
+
let builder = db.db
|
|
14
|
+
.selectFrom('quote')
|
|
15
|
+
.where('quote.subject', '=', subject.uri)
|
|
16
|
+
.select(['quote.uri', 'quote.cid', 'quote.sortAt'])
|
|
17
|
+
|
|
18
|
+
const keyset = new TimeCidKeyset(ref('quote.sortAt'), ref('quote.cid'))
|
|
19
|
+
builder = paginate(builder, {
|
|
20
|
+
limit,
|
|
21
|
+
cursor,
|
|
22
|
+
keyset,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const quotes = await builder.execute()
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
refs: quotes.map((q) => ({ uri: q.uri, cid: q.cid })),
|
|
29
|
+
cursor: keyset.packFromResult(quotes),
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
})
|
|
@@ -20,6 +20,7 @@ export default (db: Database): Partial<ServiceImpl<typeof Service>> => ({
|
|
|
20
20
|
getProfileRecords: getRecords(db, ids.AppBskyActorProfile),
|
|
21
21
|
getRepostRecords: getRecords(db, ids.AppBskyFeedRepost),
|
|
22
22
|
getThreadGateRecords: getRecords(db, ids.AppBskyFeedThreadgate),
|
|
23
|
+
getPostGateRecords: getRecords(db, ids.AppBskyFeedPostgate),
|
|
23
24
|
getLabelerRecords: getRecords(db, ids.AppBskyLabelerService),
|
|
24
25
|
getActorChatDeclarationRecords: getRecords(db, ids.ChatBskyActorDeclaration),
|
|
25
26
|
getStarterPackRecords: getRecords(db, ids.AppBskyGraphStarterpack),
|
|
@@ -74,7 +75,13 @@ export const getPostRecords = (db: Database) => {
|
|
|
74
75
|
? await db.db
|
|
75
76
|
.selectFrom('post')
|
|
76
77
|
.where('uri', 'in', req.uris)
|
|
77
|
-
.select([
|
|
78
|
+
.select([
|
|
79
|
+
'uri',
|
|
80
|
+
'violatesThreadGate',
|
|
81
|
+
'violatesEmbeddingRules',
|
|
82
|
+
'hasThreadGate',
|
|
83
|
+
'hasPostGate',
|
|
84
|
+
])
|
|
78
85
|
.execute()
|
|
79
86
|
: [],
|
|
80
87
|
])
|
|
@@ -82,6 +89,9 @@ export const getPostRecords = (db: Database) => {
|
|
|
82
89
|
const meta = req.uris.map((uri) => {
|
|
83
90
|
return new PostRecordMeta({
|
|
84
91
|
violatesThreadGate: !!byKey[uri]?.violatesThreadGate,
|
|
92
|
+
violatesEmbeddingRules: !!byKey[uri]?.violatesEmbeddingRules,
|
|
93
|
+
hasThreadGate: !!byKey[uri]?.hasThreadGate,
|
|
94
|
+
hasPostGate: !!byKey[uri]?.hasPostGate,
|
|
85
95
|
})
|
|
86
96
|
})
|
|
87
97
|
return { records, meta }
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { sql } from 'kysely'
|
|
2
|
-
import { AtUri } from '@atproto/syntax'
|
|
3
|
-
import { ids } from '../../lexicon/lexicons'
|
|
4
2
|
import {
|
|
5
3
|
Record as PostRecord,
|
|
6
4
|
ReplyRef,
|
|
@@ -144,9 +142,3 @@ export const violatesThreadGate = async (
|
|
|
144
142
|
|
|
145
143
|
return true
|
|
146
144
|
}
|
|
147
|
-
|
|
148
|
-
export const postToThreadgateUri = (postUri: string) => {
|
|
149
|
-
const gateUri = new AtUri(postUri)
|
|
150
|
-
gateUri.collection = ids.AppBskyFeedThreadgate
|
|
151
|
-
return gateUri.toString()
|
|
152
|
-
}
|
package/src/hydration/feed.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Record as LikeRecord } from '../lexicon/types/app/bsky/feed/like'
|
|
|
4
4
|
import { Record as RepostRecord } from '../lexicon/types/app/bsky/feed/repost'
|
|
5
5
|
import { Record as FeedGenRecord } from '../lexicon/types/app/bsky/feed/generator'
|
|
6
6
|
import { Record as ThreadgateRecord } from '../lexicon/types/app/bsky/feed/threadgate'
|
|
7
|
+
import { Record as PostgateRecord } from '../lexicon/types/app/bsky/feed/postgate'
|
|
7
8
|
import {
|
|
8
9
|
HydrationMap,
|
|
9
10
|
ItemRef,
|
|
@@ -12,11 +13,15 @@ import {
|
|
|
12
13
|
parseString,
|
|
13
14
|
split,
|
|
14
15
|
} from './util'
|
|
15
|
-
import { AtUri } from '@atproto/syntax'
|
|
16
|
-
import { ids } from '../lexicon/lexicons'
|
|
17
16
|
import { dedupeStrs } from '@atproto/common'
|
|
17
|
+
import { postUriToThreadgateUri, postUriToPostgateUri } from '../util/uris'
|
|
18
18
|
|
|
19
|
-
export type Post = RecordInfo<PostRecord> & {
|
|
19
|
+
export type Post = RecordInfo<PostRecord> & {
|
|
20
|
+
violatesThreadGate: boolean
|
|
21
|
+
violatesEmbeddingRules: boolean
|
|
22
|
+
hasThreadGate: boolean
|
|
23
|
+
hasPostGate: boolean
|
|
24
|
+
}
|
|
20
25
|
export type Posts = HydrationMap<Post>
|
|
21
26
|
|
|
22
27
|
export type PostViewerState = {
|
|
@@ -31,6 +36,7 @@ export type PostAgg = {
|
|
|
31
36
|
likes: number
|
|
32
37
|
replies: number
|
|
33
38
|
reposts: number
|
|
39
|
+
quotes: number
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
export type PostAggs = HydrationMap<PostAgg>
|
|
@@ -58,6 +64,8 @@ export type FeedGenViewerStates = HydrationMap<FeedGenViewerState>
|
|
|
58
64
|
|
|
59
65
|
export type Threadgate = RecordInfo<ThreadgateRecord>
|
|
60
66
|
export type Threadgates = HydrationMap<Threadgate>
|
|
67
|
+
export type Postgate = RecordInfo<PostgateRecord>
|
|
68
|
+
export type Postgates = HydrationMap<Postgate>
|
|
61
69
|
|
|
62
70
|
export type ThreadRef = ItemRef & { threadRoot: string }
|
|
63
71
|
|
|
@@ -83,7 +91,21 @@ export class FeedHydrator {
|
|
|
83
91
|
return need.reduce((acc, uri, i) => {
|
|
84
92
|
const record = parseRecord<PostRecord>(res.records[i], includeTakedowns)
|
|
85
93
|
const violatesThreadGate = res.meta[i].violatesThreadGate
|
|
86
|
-
|
|
94
|
+
const violatesEmbeddingRules = res.meta[i].violatesEmbeddingRules
|
|
95
|
+
const hasThreadGate = res.meta[i].hasThreadGate
|
|
96
|
+
const hasPostGate = res.meta[i].hasPostGate
|
|
97
|
+
return acc.set(
|
|
98
|
+
uri,
|
|
99
|
+
record
|
|
100
|
+
? {
|
|
101
|
+
...record,
|
|
102
|
+
violatesThreadGate,
|
|
103
|
+
violatesEmbeddingRules,
|
|
104
|
+
hasThreadGate,
|
|
105
|
+
hasPostGate,
|
|
106
|
+
}
|
|
107
|
+
: null,
|
|
108
|
+
)
|
|
87
109
|
}, base)
|
|
88
110
|
}
|
|
89
111
|
|
|
@@ -135,6 +157,7 @@ export class FeedHydrator {
|
|
|
135
157
|
likes: counts.likes[i] ?? 0,
|
|
136
158
|
reposts: counts.reposts[i] ?? 0,
|
|
137
159
|
replies: counts.replies[i] ?? 0,
|
|
160
|
+
quotes: counts.quotes[i] ?? 0,
|
|
138
161
|
})
|
|
139
162
|
}, new HydrationMap<PostAgg>())
|
|
140
163
|
}
|
|
@@ -185,14 +208,14 @@ export class FeedHydrator {
|
|
|
185
208
|
includeTakedowns = false,
|
|
186
209
|
): Promise<Threadgates> {
|
|
187
210
|
if (!postUris.length) return new HydrationMap<Threadgate>()
|
|
188
|
-
const uris = postUris.map(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
211
|
+
const uris = postUris.map(postUriToThreadgateUri)
|
|
212
|
+
return this.getThreadgateRecords(uris, includeTakedowns)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async getThreadgateRecords(
|
|
216
|
+
uris: string[],
|
|
217
|
+
includeTakedowns = false,
|
|
218
|
+
): Promise<Threadgates> {
|
|
196
219
|
const res = await this.dataplane.getThreadGateRecords({ uris })
|
|
197
220
|
return uris.reduce((acc, uri, i) => {
|
|
198
221
|
const record = parseRecord<ThreadgateRecord>(
|
|
@@ -203,6 +226,29 @@ export class FeedHydrator {
|
|
|
203
226
|
}, new HydrationMap<Threadgate>())
|
|
204
227
|
}
|
|
205
228
|
|
|
229
|
+
async getPostgatesForPosts(
|
|
230
|
+
postUris: string[],
|
|
231
|
+
includeTakedowns = false,
|
|
232
|
+
): Promise<Postgates> {
|
|
233
|
+
if (!postUris.length) return new HydrationMap<Postgate>()
|
|
234
|
+
const uris = postUris.map(postUriToPostgateUri)
|
|
235
|
+
return this.getPostgateRecords(uris, includeTakedowns)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async getPostgateRecords(
|
|
239
|
+
uris: string[],
|
|
240
|
+
includeTakedowns = false,
|
|
241
|
+
): Promise<Postgates> {
|
|
242
|
+
const res = await this.dataplane.getPostGateRecords({ uris })
|
|
243
|
+
return uris.reduce((acc, uri, i) => {
|
|
244
|
+
const record = parseRecord<PostgateRecord>(
|
|
245
|
+
res.records[i],
|
|
246
|
+
includeTakedowns,
|
|
247
|
+
)
|
|
248
|
+
return acc.set(uri, record ?? null)
|
|
249
|
+
}, new HydrationMap<Postgate>())
|
|
250
|
+
}
|
|
251
|
+
|
|
206
252
|
async getLikes(uris: string[], includeTakedowns = false): Promise<Likes> {
|
|
207
253
|
if (!uris.length) return new HydrationMap<Like>()
|
|
208
254
|
const res = await this.dataplane.getLikeRecords({ uris })
|