@atproto/bsky 0.0.25 → 0.0.27
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/buf.gen.yaml +12 -0
- package/dist/api/app/bsky/graph/getRelationships.d.ts +3 -0
- package/dist/api/app/bsky/unspecced/getTaggedSuggestions.d.ts +3 -0
- package/dist/bsync.d.ts +8 -0
- package/dist/config.d.ts +20 -0
- package/dist/context.d.ts +6 -3
- package/dist/courier.d.ts +8 -0
- package/dist/db/database-schema.d.ts +2 -1
- package/dist/db/index.js +15 -1
- package/dist/db/index.js.map +3 -3
- package/dist/db/migrations/20240124T023719200Z-tagged-suggestions.d.ts +3 -0
- package/dist/db/migrations/index.d.ts +1 -0
- package/dist/db/tables/tagged-suggestion.d.ts +9 -0
- package/dist/index.js +48246 -16828
- package/dist/index.js.map +3 -3
- package/dist/indexer/config.d.ts +8 -0
- package/dist/indexer/context.d.ts +3 -0
- package/dist/ingester/config.d.ts +8 -0
- package/dist/ingester/context.d.ts +3 -0
- package/dist/ingester/mute-subscription.d.ts +22 -0
- package/dist/lexicon/index.d.ts +4 -0
- package/dist/lexicon/lexicons.d.ts +153 -0
- package/dist/lexicon/types/app/bsky/actor/defs.d.ts +7 -1
- package/dist/lexicon/types/app/bsky/graph/defs.d.ts +15 -0
- package/dist/lexicon/types/app/bsky/graph/getRelationships.d.ts +38 -0
- package/dist/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.d.ts +39 -0
- package/dist/notifications.d.ts +27 -16
- package/dist/proto/bsync_connect.d.ts +25 -0
- package/dist/proto/bsync_pb.d.ts +90 -0
- package/dist/proto/courier_connect.d.ts +25 -0
- package/dist/proto/courier_pb.d.ts +91 -0
- package/dist/services/actor/index.d.ts +2 -2
- package/dist/services/indexing/index.d.ts +2 -2
- package/dist/services/util/post.d.ts +6 -6
- package/dist/util/retry.d.ts +2 -0
- package/package.json +15 -7
- package/proto/courier.proto +56 -0
- package/src/api/app/bsky/graph/getRelationships.ts +71 -0
- package/src/api/app/bsky/graph/muteActor.ts +32 -5
- package/src/api/app/bsky/graph/muteActorList.ts +32 -5
- package/src/api/app/bsky/graph/unmuteActor.ts +32 -5
- package/src/api/app/bsky/graph/unmuteActorList.ts +32 -5
- package/src/api/app/bsky/notification/registerPush.ts +42 -8
- package/src/api/app/bsky/unspecced/getTaggedSuggestions.ts +21 -0
- package/src/api/index.ts +4 -0
- package/src/bsync.ts +41 -0
- package/src/config.ts +79 -0
- package/src/context.ts +12 -6
- package/src/courier.ts +41 -0
- package/src/db/database-schema.ts +2 -0
- package/src/db/migrations/20240124T023719200Z-tagged-suggestions.ts +15 -0
- package/src/db/migrations/index.ts +1 -0
- package/src/db/tables/tagged-suggestion.ts +11 -0
- package/src/index.ts +26 -3
- package/src/indexer/config.ts +36 -0
- package/src/indexer/context.ts +6 -0
- package/src/indexer/index.ts +27 -3
- package/src/ingester/config.ts +34 -0
- package/src/ingester/context.ts +6 -0
- package/src/ingester/index.ts +18 -0
- package/src/ingester/mute-subscription.ts +213 -0
- package/src/lexicon/index.ts +24 -0
- package/src/lexicon/lexicons.ts +167 -0
- package/src/lexicon/types/app/bsky/actor/defs.ts +19 -0
- package/src/lexicon/types/app/bsky/graph/defs.ts +41 -0
- package/src/lexicon/types/app/bsky/graph/getRelationships.ts +53 -0
- package/src/lexicon/types/app/bsky/unspecced/getTaggedSuggestions.ts +65 -0
- package/src/notifications.ts +165 -149
- package/src/proto/bsync_connect.ts +54 -0
- package/src/proto/bsync_pb.ts +459 -0
- package/src/proto/courier_connect.ts +50 -0
- package/src/proto/courier_pb.ts +473 -0
- package/src/services/actor/index.ts +17 -2
- package/src/services/indexing/processor.ts +1 -1
- package/src/util/retry.ts +12 -0
- package/tests/notification-server.test.ts +59 -19
- package/tests/subscription/mutes.test.ts +170 -0
- package/tests/views/__snapshots__/follows.test.ts.snap +28 -0
- package/tests/views/follows.test.ts +10 -0
- package/tests/views/suggestions.test.ts +22 -0
package/src/ingester/config.ts
CHANGED
|
@@ -10,6 +10,10 @@ export interface IngesterConfigValues {
|
|
|
10
10
|
redisPassword?: string
|
|
11
11
|
repoProvider: string
|
|
12
12
|
labelProvider?: string
|
|
13
|
+
bsyncUrl?: string
|
|
14
|
+
bsyncApiKey?: string
|
|
15
|
+
bsyncHttpVersion?: '1.1' | '2'
|
|
16
|
+
bsyncIgnoreBadTls?: boolean
|
|
13
17
|
ingesterPartitionCount: number
|
|
14
18
|
ingesterNamespace?: string
|
|
15
19
|
ingesterSubLockId?: number
|
|
@@ -42,6 +46,16 @@ export class IngesterConfig {
|
|
|
42
46
|
overrides?.redisPassword || process.env.REDIS_PASSWORD || undefined
|
|
43
47
|
const repoProvider = overrides?.repoProvider || process.env.REPO_PROVIDER // E.g. ws://abc.com:4000
|
|
44
48
|
const labelProvider = overrides?.labelProvider || process.env.LABEL_PROVIDER
|
|
49
|
+
const bsyncUrl =
|
|
50
|
+
overrides?.bsyncUrl || process.env.BSKY_BSYNC_URL || undefined
|
|
51
|
+
const bsyncApiKey =
|
|
52
|
+
overrides?.bsyncApiKey || process.env.BSKY_BSYNC_API_KEY || undefined
|
|
53
|
+
const bsyncHttpVersion =
|
|
54
|
+
overrides?.bsyncHttpVersion || process.env.BSKY_BSYNC_HTTP_VERSION || '2'
|
|
55
|
+
const bsyncIgnoreBadTls =
|
|
56
|
+
overrides?.bsyncIgnoreBadTls ||
|
|
57
|
+
process.env.BSKY_BSYNC_IGNORE_BAD_TLS === 'true'
|
|
58
|
+
assert(bsyncHttpVersion === '1.1' || bsyncHttpVersion === '2')
|
|
45
59
|
const ingesterPartitionCount =
|
|
46
60
|
overrides?.ingesterPartitionCount ||
|
|
47
61
|
maybeParseInt(process.env.INGESTER_PARTITION_COUNT)
|
|
@@ -72,6 +86,10 @@ export class IngesterConfig {
|
|
|
72
86
|
redisPassword,
|
|
73
87
|
repoProvider,
|
|
74
88
|
labelProvider,
|
|
89
|
+
bsyncUrl,
|
|
90
|
+
bsyncApiKey,
|
|
91
|
+
bsyncHttpVersion,
|
|
92
|
+
bsyncIgnoreBadTls,
|
|
75
93
|
ingesterPartitionCount,
|
|
76
94
|
ingesterSubLockId,
|
|
77
95
|
ingesterNamespace,
|
|
@@ -117,6 +135,22 @@ export class IngesterConfig {
|
|
|
117
135
|
return this.cfg.labelProvider
|
|
118
136
|
}
|
|
119
137
|
|
|
138
|
+
get bsyncUrl() {
|
|
139
|
+
return this.cfg.bsyncUrl
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
get bsyncApiKey() {
|
|
143
|
+
return this.cfg.bsyncApiKey
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
get bsyncHttpVersion() {
|
|
147
|
+
return this.cfg.bsyncHttpVersion
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
get bsyncIgnoreBadTls() {
|
|
151
|
+
return this.cfg.bsyncIgnoreBadTls
|
|
152
|
+
}
|
|
153
|
+
|
|
120
154
|
get ingesterPartitionCount() {
|
|
121
155
|
return this.cfg.ingesterPartitionCount
|
|
122
156
|
}
|
package/src/ingester/context.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { PrimaryDatabase } from '../db'
|
|
|
2
2
|
import { Redis } from '../redis'
|
|
3
3
|
import { IngesterConfig } from './config'
|
|
4
4
|
import { LabelSubscription } from './label-subscription'
|
|
5
|
+
import { MuteSubscription } from './mute-subscription'
|
|
5
6
|
|
|
6
7
|
export class IngesterContext {
|
|
7
8
|
constructor(
|
|
@@ -10,6 +11,7 @@ export class IngesterContext {
|
|
|
10
11
|
redis: Redis
|
|
11
12
|
cfg: IngesterConfig
|
|
12
13
|
labelSubscription?: LabelSubscription
|
|
14
|
+
muteSubscription?: MuteSubscription
|
|
13
15
|
},
|
|
14
16
|
) {}
|
|
15
17
|
|
|
@@ -28,6 +30,10 @@ export class IngesterContext {
|
|
|
28
30
|
get labelSubscription(): LabelSubscription | undefined {
|
|
29
31
|
return this.opts.labelSubscription
|
|
30
32
|
}
|
|
33
|
+
|
|
34
|
+
get muteSubscription(): MuteSubscription | undefined {
|
|
35
|
+
return this.opts.muteSubscription
|
|
36
|
+
}
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
export default IngesterContext
|
package/src/ingester/index.ts
CHANGED
|
@@ -5,7 +5,9 @@ import { Redis } from '../redis'
|
|
|
5
5
|
import { IngesterConfig } from './config'
|
|
6
6
|
import { IngesterContext } from './context'
|
|
7
7
|
import { IngesterSubscription } from './subscription'
|
|
8
|
+
import { authWithApiKey, createBsyncClient } from '../bsync'
|
|
8
9
|
import { LabelSubscription } from './label-subscription'
|
|
10
|
+
import { MuteSubscription } from './mute-subscription'
|
|
9
11
|
|
|
10
12
|
export { IngesterConfig } from './config'
|
|
11
13
|
export type { IngesterConfigValues } from './config'
|
|
@@ -27,14 +29,28 @@ export class BskyIngester {
|
|
|
27
29
|
cfg: IngesterConfig
|
|
28
30
|
}): BskyIngester {
|
|
29
31
|
const { db, redis, cfg } = opts
|
|
32
|
+
const bsyncClient = cfg.bsyncUrl
|
|
33
|
+
? createBsyncClient({
|
|
34
|
+
baseUrl: cfg.bsyncUrl,
|
|
35
|
+
httpVersion: cfg.bsyncHttpVersion ?? '2',
|
|
36
|
+
nodeOptions: { rejectUnauthorized: !cfg.bsyncIgnoreBadTls },
|
|
37
|
+
interceptors: cfg.bsyncApiKey
|
|
38
|
+
? [authWithApiKey(cfg.bsyncApiKey)]
|
|
39
|
+
: [],
|
|
40
|
+
})
|
|
41
|
+
: undefined
|
|
30
42
|
const labelSubscription = cfg.labelProvider
|
|
31
43
|
? new LabelSubscription(db, cfg.labelProvider)
|
|
32
44
|
: undefined
|
|
45
|
+
const muteSubscription = bsyncClient
|
|
46
|
+
? new MuteSubscription(db, redis, bsyncClient)
|
|
47
|
+
: undefined
|
|
33
48
|
const ctx = new IngesterContext({
|
|
34
49
|
db,
|
|
35
50
|
redis,
|
|
36
51
|
cfg,
|
|
37
52
|
labelSubscription,
|
|
53
|
+
muteSubscription,
|
|
38
54
|
})
|
|
39
55
|
const sub = new IngesterSubscription(ctx, {
|
|
40
56
|
service: cfg.repoProvider,
|
|
@@ -73,11 +89,13 @@ export class BskyIngester {
|
|
|
73
89
|
)
|
|
74
90
|
}, 500)
|
|
75
91
|
await this.ctx.labelSubscription?.start()
|
|
92
|
+
await this.ctx.muteSubscription?.start()
|
|
76
93
|
this.sub.run()
|
|
77
94
|
return this
|
|
78
95
|
}
|
|
79
96
|
|
|
80
97
|
async destroy(opts?: { skipDb: boolean }): Promise<void> {
|
|
98
|
+
await this.ctx.muteSubscription?.destroy()
|
|
81
99
|
await this.ctx.labelSubscription?.destroy()
|
|
82
100
|
await this.sub.destroy()
|
|
83
101
|
clearInterval(this.subStatsInterval)
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import assert from 'node:assert'
|
|
2
|
+
import { PrimaryDatabase } from '../db'
|
|
3
|
+
import { Redis } from '../redis'
|
|
4
|
+
import { BsyncClient, Code, isBsyncError } from '../bsync'
|
|
5
|
+
import { MuteOperation, MuteOperation_Type } from '../proto/bsync_pb'
|
|
6
|
+
import logger from './logger'
|
|
7
|
+
import { wait } from '@atproto/common'
|
|
8
|
+
import {
|
|
9
|
+
AtUri,
|
|
10
|
+
InvalidDidError,
|
|
11
|
+
ensureValidAtUri,
|
|
12
|
+
ensureValidDid,
|
|
13
|
+
} from '@atproto/syntax'
|
|
14
|
+
import { ids } from '../lexicon/lexicons'
|
|
15
|
+
|
|
16
|
+
const CURSOR_KEY = 'ingester:mute:cursor'
|
|
17
|
+
|
|
18
|
+
export class MuteSubscription {
|
|
19
|
+
ac = new AbortController()
|
|
20
|
+
running: Promise<void> | undefined
|
|
21
|
+
cursor: string | null = null
|
|
22
|
+
|
|
23
|
+
constructor(
|
|
24
|
+
public db: PrimaryDatabase,
|
|
25
|
+
public redis: Redis,
|
|
26
|
+
public bsyncClient: BsyncClient,
|
|
27
|
+
) {}
|
|
28
|
+
|
|
29
|
+
async start() {
|
|
30
|
+
if (this.running) return
|
|
31
|
+
this.ac = new AbortController()
|
|
32
|
+
this.running = this.run()
|
|
33
|
+
.catch((err) => {
|
|
34
|
+
// allow this to cause an unhandled rejection, let deployment handle the crash.
|
|
35
|
+
logger.error({ err }, 'mute subscription crashed')
|
|
36
|
+
throw err
|
|
37
|
+
})
|
|
38
|
+
.finally(() => (this.running = undefined))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private async run() {
|
|
42
|
+
this.cursor = await this.getCursor()
|
|
43
|
+
while (!this.ac.signal.aborted) {
|
|
44
|
+
try {
|
|
45
|
+
// get page of mute ops, long-polling
|
|
46
|
+
const page = await this.bsyncClient.scanMuteOperations(
|
|
47
|
+
{
|
|
48
|
+
limit: 100,
|
|
49
|
+
cursor: this.cursor ?? undefined,
|
|
50
|
+
},
|
|
51
|
+
{ signal: this.ac.signal },
|
|
52
|
+
)
|
|
53
|
+
if (!page.cursor) {
|
|
54
|
+
throw new BadResponseError('cursor is missing')
|
|
55
|
+
}
|
|
56
|
+
// process
|
|
57
|
+
const now = new Date()
|
|
58
|
+
for (const op of page.operations) {
|
|
59
|
+
if (this.ac.signal.aborted) return
|
|
60
|
+
if (op.type === MuteOperation_Type.ADD) {
|
|
61
|
+
await this.handleAddOp(op, now)
|
|
62
|
+
} else if (op.type === MuteOperation_Type.REMOVE) {
|
|
63
|
+
await this.handleRemoveOp(op)
|
|
64
|
+
} else if (op.type === MuteOperation_Type.CLEAR) {
|
|
65
|
+
await this.handleClearOp(op)
|
|
66
|
+
} else {
|
|
67
|
+
logger.warn(
|
|
68
|
+
{ id: op.id, type: op.type },
|
|
69
|
+
'unknown mute subscription op type',
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// update cursor
|
|
74
|
+
await this.setCursor(page.cursor)
|
|
75
|
+
this.cursor = page.cursor
|
|
76
|
+
} catch (err) {
|
|
77
|
+
if (isBsyncError(err, Code.Canceled)) {
|
|
78
|
+
return // canceled, probably from destroy()
|
|
79
|
+
}
|
|
80
|
+
if (err instanceof BadResponseError) {
|
|
81
|
+
logger.warn({ err }, 'bad response from bsync')
|
|
82
|
+
} else {
|
|
83
|
+
logger.error({ err }, 'unexpected error processing mute subscription')
|
|
84
|
+
}
|
|
85
|
+
await wait(1000) // wait a second before trying again
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async handleAddOp(op: MuteOperation, createdAt: Date) {
|
|
91
|
+
assert(op.type === MuteOperation_Type.ADD)
|
|
92
|
+
if (!isValidDid(op.actorDid)) {
|
|
93
|
+
logger.warn({ id: op.id, type: op.type }, 'bad actor in mute op')
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
if (isValidDid(op.subject)) {
|
|
97
|
+
await this.db.db
|
|
98
|
+
.insertInto('mute')
|
|
99
|
+
.values({
|
|
100
|
+
subjectDid: op.subject,
|
|
101
|
+
mutedByDid: op.actorDid,
|
|
102
|
+
createdAt: createdAt.toISOString(),
|
|
103
|
+
})
|
|
104
|
+
.onConflict((oc) => oc.doNothing())
|
|
105
|
+
.execute()
|
|
106
|
+
} else {
|
|
107
|
+
const listUri = isValidAtUri(op.subject)
|
|
108
|
+
? new AtUri(op.subject)
|
|
109
|
+
: undefined
|
|
110
|
+
if (listUri?.collection !== ids.AppBskyGraphList) {
|
|
111
|
+
logger.warn({ id: op.id, type: op.type }, 'bad subject in mute op')
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
await this.db.db
|
|
115
|
+
.insertInto('list_mute')
|
|
116
|
+
.values({
|
|
117
|
+
listUri: op.subject,
|
|
118
|
+
mutedByDid: op.actorDid,
|
|
119
|
+
createdAt: createdAt.toISOString(),
|
|
120
|
+
})
|
|
121
|
+
.onConflict((oc) => oc.doNothing())
|
|
122
|
+
.execute()
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async handleRemoveOp(op: MuteOperation) {
|
|
127
|
+
assert(op.type === MuteOperation_Type.REMOVE)
|
|
128
|
+
if (!isValidDid(op.actorDid)) {
|
|
129
|
+
logger.warn({ id: op.id, type: op.type }, 'bad actor in mute op')
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
if (isValidDid(op.subject)) {
|
|
133
|
+
await this.db.db
|
|
134
|
+
.deleteFrom('mute')
|
|
135
|
+
.where('subjectDid', '=', op.subject)
|
|
136
|
+
.where('mutedByDid', '=', op.actorDid)
|
|
137
|
+
.execute()
|
|
138
|
+
} else {
|
|
139
|
+
const listUri = isValidAtUri(op.subject)
|
|
140
|
+
? new AtUri(op.subject)
|
|
141
|
+
: undefined
|
|
142
|
+
if (listUri?.collection !== ids.AppBskyGraphList) {
|
|
143
|
+
logger.warn({ id: op.id, type: op.type }, 'bad subject in mute op')
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
await this.db.db
|
|
147
|
+
.deleteFrom('list_mute')
|
|
148
|
+
.where('listUri', '=', op.subject)
|
|
149
|
+
.where('mutedByDid', '=', op.actorDid)
|
|
150
|
+
.execute()
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async handleClearOp(op: MuteOperation) {
|
|
155
|
+
assert(op.type === MuteOperation_Type.CLEAR)
|
|
156
|
+
if (!isValidDid(op.actorDid)) {
|
|
157
|
+
logger.warn({ id: op.id, type: op.type }, 'bad actor in mute op')
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
if (op.subject) {
|
|
161
|
+
logger.warn({ id: op.id, type: op.type }, 'bad subject in mute op')
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
await this.db.db
|
|
165
|
+
.deleteFrom('mute')
|
|
166
|
+
.where('mutedByDid', '=', op.actorDid)
|
|
167
|
+
.execute()
|
|
168
|
+
await this.db.db
|
|
169
|
+
.deleteFrom('list_mute')
|
|
170
|
+
.where('mutedByDid', '=', op.actorDid)
|
|
171
|
+
.execute()
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async getCursor(): Promise<string | null> {
|
|
175
|
+
return await this.redis.get(CURSOR_KEY)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async setCursor(cursor: string): Promise<void> {
|
|
179
|
+
await this.redis.set(CURSOR_KEY, cursor)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async destroy() {
|
|
183
|
+
this.ac.abort()
|
|
184
|
+
await this.running
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
get destroyed() {
|
|
188
|
+
return this.ac.signal.aborted
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
class BadResponseError extends Error {}
|
|
193
|
+
|
|
194
|
+
const isValidDid = (did: string) => {
|
|
195
|
+
try {
|
|
196
|
+
ensureValidDid(did)
|
|
197
|
+
return true
|
|
198
|
+
} catch (err) {
|
|
199
|
+
if (err instanceof InvalidDidError) {
|
|
200
|
+
return false
|
|
201
|
+
}
|
|
202
|
+
throw err
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const isValidAtUri = (uri: string) => {
|
|
207
|
+
try {
|
|
208
|
+
ensureValidAtUri(uri)
|
|
209
|
+
return true
|
|
210
|
+
} catch {
|
|
211
|
+
return false
|
|
212
|
+
}
|
|
213
|
+
}
|
package/src/lexicon/index.ts
CHANGED
|
@@ -114,6 +114,7 @@ import * as AppBskyGraphGetListBlocks from './types/app/bsky/graph/getListBlocks
|
|
|
114
114
|
import * as AppBskyGraphGetListMutes from './types/app/bsky/graph/getListMutes'
|
|
115
115
|
import * as AppBskyGraphGetLists from './types/app/bsky/graph/getLists'
|
|
116
116
|
import * as AppBskyGraphGetMutes from './types/app/bsky/graph/getMutes'
|
|
117
|
+
import * as AppBskyGraphGetRelationships from './types/app/bsky/graph/getRelationships'
|
|
117
118
|
import * as AppBskyGraphGetSuggestedFollowsByActor from './types/app/bsky/graph/getSuggestedFollowsByActor'
|
|
118
119
|
import * as AppBskyGraphMuteActor from './types/app/bsky/graph/muteActor'
|
|
119
120
|
import * as AppBskyGraphMuteActorList from './types/app/bsky/graph/muteActorList'
|
|
@@ -124,6 +125,7 @@ import * as AppBskyNotificationListNotifications from './types/app/bsky/notifica
|
|
|
124
125
|
import * as AppBskyNotificationRegisterPush from './types/app/bsky/notification/registerPush'
|
|
125
126
|
import * as AppBskyNotificationUpdateSeen from './types/app/bsky/notification/updateSeen'
|
|
126
127
|
import * as AppBskyUnspeccedGetPopularFeedGenerators from './types/app/bsky/unspecced/getPopularFeedGenerators'
|
|
128
|
+
import * as AppBskyUnspeccedGetTaggedSuggestions from './types/app/bsky/unspecced/getTaggedSuggestions'
|
|
127
129
|
import * as AppBskyUnspeccedGetTimelineSkeleton from './types/app/bsky/unspecced/getTimelineSkeleton'
|
|
128
130
|
import * as AppBskyUnspeccedSearchActorsSkeleton from './types/app/bsky/unspecced/searchActorsSkeleton'
|
|
129
131
|
import * as AppBskyUnspeccedSearchPostsSkeleton from './types/app/bsky/unspecced/searchPostsSkeleton'
|
|
@@ -1479,6 +1481,17 @@ export class AppBskyGraphNS {
|
|
|
1479
1481
|
return this._server.xrpc.method(nsid, cfg)
|
|
1480
1482
|
}
|
|
1481
1483
|
|
|
1484
|
+
getRelationships<AV extends AuthVerifier>(
|
|
1485
|
+
cfg: ConfigOf<
|
|
1486
|
+
AV,
|
|
1487
|
+
AppBskyGraphGetRelationships.Handler<ExtractAuth<AV>>,
|
|
1488
|
+
AppBskyGraphGetRelationships.HandlerReqCtx<ExtractAuth<AV>>
|
|
1489
|
+
>,
|
|
1490
|
+
) {
|
|
1491
|
+
const nsid = 'app.bsky.graph.getRelationships' // @ts-ignore
|
|
1492
|
+
return this._server.xrpc.method(nsid, cfg)
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1482
1495
|
getSuggestedFollowsByActor<AV extends AuthVerifier>(
|
|
1483
1496
|
cfg: ConfigOf<
|
|
1484
1497
|
AV,
|
|
@@ -1613,6 +1626,17 @@ export class AppBskyUnspeccedNS {
|
|
|
1613
1626
|
return this._server.xrpc.method(nsid, cfg)
|
|
1614
1627
|
}
|
|
1615
1628
|
|
|
1629
|
+
getTaggedSuggestions<AV extends AuthVerifier>(
|
|
1630
|
+
cfg: ConfigOf<
|
|
1631
|
+
AV,
|
|
1632
|
+
AppBskyUnspeccedGetTaggedSuggestions.Handler<ExtractAuth<AV>>,
|
|
1633
|
+
AppBskyUnspeccedGetTaggedSuggestions.HandlerReqCtx<ExtractAuth<AV>>
|
|
1634
|
+
>,
|
|
1635
|
+
) {
|
|
1636
|
+
const nsid = 'app.bsky.unspecced.getTaggedSuggestions' // @ts-ignore
|
|
1637
|
+
return this._server.xrpc.method(nsid, cfg)
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1616
1640
|
getTimelineSkeleton<AV extends AuthVerifier>(
|
|
1617
1641
|
cfg: ConfigOf<
|
|
1618
1642
|
AV,
|
package/src/lexicon/lexicons.ts
CHANGED
|
@@ -4615,6 +4615,7 @@ export const schemaDict = {
|
|
|
4615
4615
|
'lex:app.bsky.actor.defs#personalDetailsPref',
|
|
4616
4616
|
'lex:app.bsky.actor.defs#feedViewPref',
|
|
4617
4617
|
'lex:app.bsky.actor.defs#threadViewPref',
|
|
4618
|
+
'lex:app.bsky.actor.defs#interestsPref',
|
|
4618
4619
|
],
|
|
4619
4620
|
},
|
|
4620
4621
|
},
|
|
@@ -4718,6 +4719,23 @@ export const schemaDict = {
|
|
|
4718
4719
|
},
|
|
4719
4720
|
},
|
|
4720
4721
|
},
|
|
4722
|
+
interestsPref: {
|
|
4723
|
+
type: 'object',
|
|
4724
|
+
required: ['tags'],
|
|
4725
|
+
properties: {
|
|
4726
|
+
tags: {
|
|
4727
|
+
type: 'array',
|
|
4728
|
+
maxLength: 100,
|
|
4729
|
+
items: {
|
|
4730
|
+
type: 'string',
|
|
4731
|
+
maxLength: 640,
|
|
4732
|
+
maxGraphemes: 64,
|
|
4733
|
+
},
|
|
4734
|
+
description:
|
|
4735
|
+
"A list of tags which describe the account owner's interests gathered during onboarding.",
|
|
4736
|
+
},
|
|
4737
|
+
},
|
|
4738
|
+
},
|
|
4721
4739
|
},
|
|
4722
4740
|
},
|
|
4723
4741
|
AppBskyActorGetPreferences: {
|
|
@@ -6925,6 +6943,45 @@ export const schemaDict = {
|
|
|
6925
6943
|
},
|
|
6926
6944
|
},
|
|
6927
6945
|
},
|
|
6946
|
+
notFoundActor: {
|
|
6947
|
+
type: 'object',
|
|
6948
|
+
description: 'indicates that a handle or DID could not be resolved',
|
|
6949
|
+
required: ['actor', 'notFound'],
|
|
6950
|
+
properties: {
|
|
6951
|
+
actor: {
|
|
6952
|
+
type: 'string',
|
|
6953
|
+
format: 'at-identifier',
|
|
6954
|
+
},
|
|
6955
|
+
notFound: {
|
|
6956
|
+
type: 'boolean',
|
|
6957
|
+
const: true,
|
|
6958
|
+
},
|
|
6959
|
+
},
|
|
6960
|
+
},
|
|
6961
|
+
relationship: {
|
|
6962
|
+
type: 'object',
|
|
6963
|
+
description:
|
|
6964
|
+
'lists the bi-directional graph relationships between one actor (not indicated in the object), and the target actors (the DID included in the object)',
|
|
6965
|
+
required: ['did'],
|
|
6966
|
+
properties: {
|
|
6967
|
+
did: {
|
|
6968
|
+
type: 'string',
|
|
6969
|
+
format: 'did',
|
|
6970
|
+
},
|
|
6971
|
+
following: {
|
|
6972
|
+
type: 'string',
|
|
6973
|
+
format: 'at-uri',
|
|
6974
|
+
description:
|
|
6975
|
+
'if the actor follows this DID, this is the AT-URI of the follow record',
|
|
6976
|
+
},
|
|
6977
|
+
followedBy: {
|
|
6978
|
+
type: 'string',
|
|
6979
|
+
format: 'at-uri',
|
|
6980
|
+
description:
|
|
6981
|
+
'if the actor is followed by this DID, contains the AT-URI of the follow record',
|
|
6982
|
+
},
|
|
6983
|
+
},
|
|
6984
|
+
},
|
|
6928
6985
|
},
|
|
6929
6986
|
},
|
|
6930
6987
|
AppBskyGraphFollow: {
|
|
@@ -7328,6 +7385,65 @@ export const schemaDict = {
|
|
|
7328
7385
|
},
|
|
7329
7386
|
},
|
|
7330
7387
|
},
|
|
7388
|
+
AppBskyGraphGetRelationships: {
|
|
7389
|
+
lexicon: 1,
|
|
7390
|
+
id: 'app.bsky.graph.getRelationships',
|
|
7391
|
+
defs: {
|
|
7392
|
+
main: {
|
|
7393
|
+
type: 'query',
|
|
7394
|
+
description:
|
|
7395
|
+
'Enumerates public relationships between one account, and a list of other accounts',
|
|
7396
|
+
parameters: {
|
|
7397
|
+
type: 'params',
|
|
7398
|
+
required: ['actor'],
|
|
7399
|
+
properties: {
|
|
7400
|
+
actor: {
|
|
7401
|
+
type: 'string',
|
|
7402
|
+
format: 'at-identifier',
|
|
7403
|
+
},
|
|
7404
|
+
others: {
|
|
7405
|
+
type: 'array',
|
|
7406
|
+
maxLength: 30,
|
|
7407
|
+
items: {
|
|
7408
|
+
type: 'string',
|
|
7409
|
+
format: 'at-identifier',
|
|
7410
|
+
},
|
|
7411
|
+
},
|
|
7412
|
+
},
|
|
7413
|
+
},
|
|
7414
|
+
output: {
|
|
7415
|
+
encoding: 'application/json',
|
|
7416
|
+
schema: {
|
|
7417
|
+
type: 'object',
|
|
7418
|
+
required: ['relationships'],
|
|
7419
|
+
properties: {
|
|
7420
|
+
actor: {
|
|
7421
|
+
type: 'string',
|
|
7422
|
+
format: 'did',
|
|
7423
|
+
},
|
|
7424
|
+
relationships: {
|
|
7425
|
+
type: 'array',
|
|
7426
|
+
items: {
|
|
7427
|
+
type: 'union',
|
|
7428
|
+
refs: [
|
|
7429
|
+
'lex:app.bsky.graph.defs#relationship',
|
|
7430
|
+
'lex:app.bsky.graph.defs#notFoundActor',
|
|
7431
|
+
],
|
|
7432
|
+
},
|
|
7433
|
+
},
|
|
7434
|
+
},
|
|
7435
|
+
},
|
|
7436
|
+
},
|
|
7437
|
+
errors: [
|
|
7438
|
+
{
|
|
7439
|
+
name: 'ActorNotFound',
|
|
7440
|
+
description:
|
|
7441
|
+
'the primary actor at-identifier could not be resolved',
|
|
7442
|
+
},
|
|
7443
|
+
],
|
|
7444
|
+
},
|
|
7445
|
+
},
|
|
7446
|
+
},
|
|
7331
7447
|
AppBskyGraphGetSuggestedFollowsByActor: {
|
|
7332
7448
|
lexicon: 1,
|
|
7333
7449
|
id: 'app.bsky.graph.getSuggestedFollowsByActor',
|
|
@@ -7908,6 +8024,54 @@ export const schemaDict = {
|
|
|
7908
8024
|
},
|
|
7909
8025
|
},
|
|
7910
8026
|
},
|
|
8027
|
+
AppBskyUnspeccedGetTaggedSuggestions: {
|
|
8028
|
+
lexicon: 1,
|
|
8029
|
+
id: 'app.bsky.unspecced.getTaggedSuggestions',
|
|
8030
|
+
defs: {
|
|
8031
|
+
main: {
|
|
8032
|
+
type: 'query',
|
|
8033
|
+
description:
|
|
8034
|
+
'Get a list of suggestions (feeds and users) tagged with categories',
|
|
8035
|
+
parameters: {
|
|
8036
|
+
type: 'params',
|
|
8037
|
+
properties: {},
|
|
8038
|
+
},
|
|
8039
|
+
output: {
|
|
8040
|
+
encoding: 'application/json',
|
|
8041
|
+
schema: {
|
|
8042
|
+
type: 'object',
|
|
8043
|
+
required: ['suggestions'],
|
|
8044
|
+
properties: {
|
|
8045
|
+
suggestions: {
|
|
8046
|
+
type: 'array',
|
|
8047
|
+
items: {
|
|
8048
|
+
type: 'ref',
|
|
8049
|
+
ref: 'lex:app.bsky.unspecced.getTaggedSuggestions#suggestion',
|
|
8050
|
+
},
|
|
8051
|
+
},
|
|
8052
|
+
},
|
|
8053
|
+
},
|
|
8054
|
+
},
|
|
8055
|
+
},
|
|
8056
|
+
suggestion: {
|
|
8057
|
+
type: 'object',
|
|
8058
|
+
required: ['tag', 'subjectType', 'subject'],
|
|
8059
|
+
properties: {
|
|
8060
|
+
tag: {
|
|
8061
|
+
type: 'string',
|
|
8062
|
+
},
|
|
8063
|
+
subjectType: {
|
|
8064
|
+
type: 'string',
|
|
8065
|
+
knownValues: ['actor', 'feed'],
|
|
8066
|
+
},
|
|
8067
|
+
subject: {
|
|
8068
|
+
type: 'string',
|
|
8069
|
+
format: 'uri',
|
|
8070
|
+
},
|
|
8071
|
+
},
|
|
8072
|
+
},
|
|
8073
|
+
},
|
|
8074
|
+
},
|
|
7911
8075
|
AppBskyUnspeccedGetTimelineSkeleton: {
|
|
7912
8076
|
lexicon: 1,
|
|
7913
8077
|
id: 'app.bsky.unspecced.getTimelineSkeleton',
|
|
@@ -8224,6 +8388,7 @@ export const ids = {
|
|
|
8224
8388
|
AppBskyGraphGetListMutes: 'app.bsky.graph.getListMutes',
|
|
8225
8389
|
AppBskyGraphGetLists: 'app.bsky.graph.getLists',
|
|
8226
8390
|
AppBskyGraphGetMutes: 'app.bsky.graph.getMutes',
|
|
8391
|
+
AppBskyGraphGetRelationships: 'app.bsky.graph.getRelationships',
|
|
8227
8392
|
AppBskyGraphGetSuggestedFollowsByActor:
|
|
8228
8393
|
'app.bsky.graph.getSuggestedFollowsByActor',
|
|
8229
8394
|
AppBskyGraphList: 'app.bsky.graph.list',
|
|
@@ -8242,6 +8407,8 @@ export const ids = {
|
|
|
8242
8407
|
AppBskyUnspeccedDefs: 'app.bsky.unspecced.defs',
|
|
8243
8408
|
AppBskyUnspeccedGetPopularFeedGenerators:
|
|
8244
8409
|
'app.bsky.unspecced.getPopularFeedGenerators',
|
|
8410
|
+
AppBskyUnspeccedGetTaggedSuggestions:
|
|
8411
|
+
'app.bsky.unspecced.getTaggedSuggestions',
|
|
8245
8412
|
AppBskyUnspeccedGetTimelineSkeleton: 'app.bsky.unspecced.getTimelineSkeleton',
|
|
8246
8413
|
AppBskyUnspeccedSearchActorsSkeleton:
|
|
8247
8414
|
'app.bsky.unspecced.searchActorsSkeleton',
|
|
@@ -112,6 +112,7 @@ export type Preferences = (
|
|
|
112
112
|
| PersonalDetailsPref
|
|
113
113
|
| FeedViewPref
|
|
114
114
|
| ThreadViewPref
|
|
115
|
+
| InterestsPref
|
|
115
116
|
| { $type: string; [k: string]: unknown }
|
|
116
117
|
)[]
|
|
117
118
|
|
|
@@ -233,3 +234,21 @@ export function isThreadViewPref(v: unknown): v is ThreadViewPref {
|
|
|
233
234
|
export function validateThreadViewPref(v: unknown): ValidationResult {
|
|
234
235
|
return lexicons.validate('app.bsky.actor.defs#threadViewPref', v)
|
|
235
236
|
}
|
|
237
|
+
|
|
238
|
+
export interface InterestsPref {
|
|
239
|
+
/** A list of tags which describe the account owner's interests gathered during onboarding. */
|
|
240
|
+
tags: string[]
|
|
241
|
+
[k: string]: unknown
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function isInterestsPref(v: unknown): v is InterestsPref {
|
|
245
|
+
return (
|
|
246
|
+
isObj(v) &&
|
|
247
|
+
hasProp(v, '$type') &&
|
|
248
|
+
v.$type === 'app.bsky.actor.defs#interestsPref'
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export function validateInterestsPref(v: unknown): ValidationResult {
|
|
253
|
+
return lexicons.validate('app.bsky.actor.defs#interestsPref', v)
|
|
254
|
+
}
|
|
@@ -102,3 +102,44 @@ export function isListViewerState(v: unknown): v is ListViewerState {
|
|
|
102
102
|
export function validateListViewerState(v: unknown): ValidationResult {
|
|
103
103
|
return lexicons.validate('app.bsky.graph.defs#listViewerState', v)
|
|
104
104
|
}
|
|
105
|
+
|
|
106
|
+
/** indicates that a handle or DID could not be resolved */
|
|
107
|
+
export interface NotFoundActor {
|
|
108
|
+
actor: string
|
|
109
|
+
notFound: true
|
|
110
|
+
[k: string]: unknown
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function isNotFoundActor(v: unknown): v is NotFoundActor {
|
|
114
|
+
return (
|
|
115
|
+
isObj(v) &&
|
|
116
|
+
hasProp(v, '$type') &&
|
|
117
|
+
v.$type === 'app.bsky.graph.defs#notFoundActor'
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function validateNotFoundActor(v: unknown): ValidationResult {
|
|
122
|
+
return lexicons.validate('app.bsky.graph.defs#notFoundActor', v)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** lists the bi-directional graph relationships between one actor (not indicated in the object), and the target actors (the DID included in the object) */
|
|
126
|
+
export interface Relationship {
|
|
127
|
+
did: string
|
|
128
|
+
/** if the actor follows this DID, this is the AT-URI of the follow record */
|
|
129
|
+
following?: string
|
|
130
|
+
/** if the actor is followed by this DID, contains the AT-URI of the follow record */
|
|
131
|
+
followedBy?: string
|
|
132
|
+
[k: string]: unknown
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function isRelationship(v: unknown): v is Relationship {
|
|
136
|
+
return (
|
|
137
|
+
isObj(v) &&
|
|
138
|
+
hasProp(v, '$type') &&
|
|
139
|
+
v.$type === 'app.bsky.graph.defs#relationship'
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function validateRelationship(v: unknown): ValidationResult {
|
|
144
|
+
return lexicons.validate('app.bsky.graph.defs#relationship', v)
|
|
145
|
+
}
|