@atproto/bsky 0.0.25 → 0.0.26
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 +7 -0
- package/buf.gen.yaml +12 -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 +47930 -16807
- 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 +2 -0
- package/dist/lexicon/lexicons.d.ts +48 -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/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 +2 -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 +12 -0
- package/src/lexicon/lexicons.ts +50 -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/suggestions.test.ts +22 -0
package/src/config.ts
CHANGED
|
@@ -31,6 +31,16 @@ export interface ServerConfigValues {
|
|
|
31
31
|
imgUriEndpoint?: string
|
|
32
32
|
blobCacheLocation?: string
|
|
33
33
|
searchEndpoint?: string
|
|
34
|
+
bsyncUrl?: string
|
|
35
|
+
bsyncApiKey?: string
|
|
36
|
+
bsyncHttpVersion?: '1.1' | '2'
|
|
37
|
+
bsyncIgnoreBadTls?: boolean
|
|
38
|
+
bsyncOnlyMutes?: boolean
|
|
39
|
+
courierUrl?: string
|
|
40
|
+
courierApiKey?: string
|
|
41
|
+
courierHttpVersion?: '1.1' | '2'
|
|
42
|
+
courierIgnoreBadTls?: boolean
|
|
43
|
+
courierOnlyRegistration?: boolean
|
|
34
44
|
adminPassword: string
|
|
35
45
|
moderatorPassword: string
|
|
36
46
|
triagePassword: string
|
|
@@ -88,6 +98,25 @@ export class ServerConfig {
|
|
|
88
98
|
const imgUriEndpoint = process.env.IMG_URI_ENDPOINT
|
|
89
99
|
const blobCacheLocation = process.env.BLOB_CACHE_LOC
|
|
90
100
|
const searchEndpoint = process.env.SEARCH_ENDPOINT
|
|
101
|
+
const bsyncUrl = process.env.BSKY_BSYNC_URL || undefined
|
|
102
|
+
const bsyncApiKey = process.env.BSKY_BSYNC_API_KEY || undefined
|
|
103
|
+
const bsyncHttpVersion = process.env.BSKY_BSYNC_HTTP_VERSION || '2'
|
|
104
|
+
const bsyncIgnoreBadTls = process.env.BSKY_BSYNC_IGNORE_BAD_TLS === 'true'
|
|
105
|
+
const bsyncOnlyMutes = process.env.BSKY_BSYNC_ONLY_MUTES === 'true'
|
|
106
|
+
assert(!bsyncOnlyMutes || bsyncUrl, 'bsync-only mutes requires a bsync url')
|
|
107
|
+
assert(bsyncHttpVersion === '1.1' || bsyncHttpVersion === '2')
|
|
108
|
+
const courierUrl = process.env.BSKY_COURIER_URL || undefined
|
|
109
|
+
const courierApiKey = process.env.BSKY_COURIER_API_KEY || undefined
|
|
110
|
+
const courierHttpVersion = process.env.BSKY_COURIER_HTTP_VERSION || '2'
|
|
111
|
+
const courierIgnoreBadTls =
|
|
112
|
+
process.env.BSKY_COURIER_IGNORE_BAD_TLS === 'true'
|
|
113
|
+
const courierOnlyRegistration =
|
|
114
|
+
process.env.BSKY_COURIER_ONLY_REGISTRATION === 'true'
|
|
115
|
+
assert(
|
|
116
|
+
!courierOnlyRegistration || courierUrl,
|
|
117
|
+
'courier-only registration requires a courier url',
|
|
118
|
+
)
|
|
119
|
+
assert(courierHttpVersion === '1.1' || courierHttpVersion === '2')
|
|
91
120
|
const dbPrimaryPostgresUrl =
|
|
92
121
|
overrides?.dbPrimaryPostgresUrl || process.env.DB_PRIMARY_POSTGRES_URL
|
|
93
122
|
let dbReplicaPostgresUrls = overrides?.dbReplicaPostgresUrls
|
|
@@ -152,6 +181,16 @@ export class ServerConfig {
|
|
|
152
181
|
imgUriEndpoint,
|
|
153
182
|
blobCacheLocation,
|
|
154
183
|
searchEndpoint,
|
|
184
|
+
bsyncUrl,
|
|
185
|
+
bsyncApiKey,
|
|
186
|
+
bsyncHttpVersion,
|
|
187
|
+
bsyncIgnoreBadTls,
|
|
188
|
+
bsyncOnlyMutes,
|
|
189
|
+
courierUrl,
|
|
190
|
+
courierApiKey,
|
|
191
|
+
courierHttpVersion,
|
|
192
|
+
courierIgnoreBadTls,
|
|
193
|
+
courierOnlyRegistration,
|
|
155
194
|
adminPassword,
|
|
156
195
|
moderatorPassword,
|
|
157
196
|
triagePassword,
|
|
@@ -268,6 +307,46 @@ export class ServerConfig {
|
|
|
268
307
|
return this.cfg.searchEndpoint
|
|
269
308
|
}
|
|
270
309
|
|
|
310
|
+
get bsyncUrl() {
|
|
311
|
+
return this.cfg.bsyncUrl
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
get bsyncApiKey() {
|
|
315
|
+
return this.cfg.bsyncApiKey
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
get bsyncOnlyMutes() {
|
|
319
|
+
return this.cfg.bsyncOnlyMutes
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
get bsyncHttpVersion() {
|
|
323
|
+
return this.cfg.bsyncHttpVersion
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
get bsyncIgnoreBadTls() {
|
|
327
|
+
return this.cfg.bsyncIgnoreBadTls
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
get courierUrl() {
|
|
331
|
+
return this.cfg.courierUrl
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
get courierApiKey() {
|
|
335
|
+
return this.cfg.courierApiKey
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
get courierHttpVersion() {
|
|
339
|
+
return this.cfg.courierHttpVersion
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
get courierIgnoreBadTls() {
|
|
343
|
+
return this.cfg.courierIgnoreBadTls
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
get courierOnlyRegistration() {
|
|
347
|
+
return this.cfg.courierOnlyRegistration
|
|
348
|
+
}
|
|
349
|
+
|
|
271
350
|
get adminPassword() {
|
|
272
351
|
return this.cfg.adminPassword
|
|
273
352
|
}
|
package/src/context.ts
CHANGED
|
@@ -10,9 +10,10 @@ import { Services } from './services'
|
|
|
10
10
|
import DidRedisCache from './did-cache'
|
|
11
11
|
import { BackgroundQueue } from './background'
|
|
12
12
|
import { MountedAlgos } from './feed-gen/types'
|
|
13
|
-
import { NotificationServer } from './notifications'
|
|
14
13
|
import { Redis } from './redis'
|
|
15
14
|
import { AuthVerifier } from './auth-verifier'
|
|
15
|
+
import { BsyncClient } from './bsync'
|
|
16
|
+
import { CourierClient } from './courier'
|
|
16
17
|
|
|
17
18
|
export class AppContext {
|
|
18
19
|
constructor(
|
|
@@ -27,8 +28,9 @@ export class AppContext {
|
|
|
27
28
|
redis: Redis
|
|
28
29
|
backgroundQueue: BackgroundQueue
|
|
29
30
|
searchAgent?: AtpAgent
|
|
31
|
+
bsyncClient?: BsyncClient
|
|
32
|
+
courierClient?: CourierClient
|
|
30
33
|
algos: MountedAlgos
|
|
31
|
-
notifServer: NotificationServer
|
|
32
34
|
authVerifier: AuthVerifier
|
|
33
35
|
},
|
|
34
36
|
) {}
|
|
@@ -69,14 +71,18 @@ export class AppContext {
|
|
|
69
71
|
return this.opts.redis
|
|
70
72
|
}
|
|
71
73
|
|
|
72
|
-
get notifServer(): NotificationServer {
|
|
73
|
-
return this.opts.notifServer
|
|
74
|
-
}
|
|
75
|
-
|
|
76
74
|
get searchAgent(): AtpAgent | undefined {
|
|
77
75
|
return this.opts.searchAgent
|
|
78
76
|
}
|
|
79
77
|
|
|
78
|
+
get bsyncClient(): BsyncClient | undefined {
|
|
79
|
+
return this.opts.bsyncClient
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get courierClient(): CourierClient | undefined {
|
|
83
|
+
return this.opts.courierClient
|
|
84
|
+
}
|
|
85
|
+
|
|
80
86
|
get authVerifier(): AuthVerifier {
|
|
81
87
|
return this.opts.authVerifier
|
|
82
88
|
}
|
package/src/courier.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Service } from './proto/courier_connect'
|
|
2
|
+
import {
|
|
3
|
+
Code,
|
|
4
|
+
ConnectError,
|
|
5
|
+
PromiseClient,
|
|
6
|
+
createPromiseClient,
|
|
7
|
+
Interceptor,
|
|
8
|
+
} from '@connectrpc/connect'
|
|
9
|
+
import {
|
|
10
|
+
createConnectTransport,
|
|
11
|
+
ConnectTransportOptions,
|
|
12
|
+
} from '@connectrpc/connect-node'
|
|
13
|
+
|
|
14
|
+
export type CourierClient = PromiseClient<typeof Service>
|
|
15
|
+
|
|
16
|
+
export const createCourierClient = (
|
|
17
|
+
opts: ConnectTransportOptions,
|
|
18
|
+
): CourierClient => {
|
|
19
|
+
const transport = createConnectTransport(opts)
|
|
20
|
+
return createPromiseClient(Service, transport)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { Code }
|
|
24
|
+
|
|
25
|
+
export const isCourierError = (
|
|
26
|
+
err: unknown,
|
|
27
|
+
code?: Code,
|
|
28
|
+
): err is ConnectError => {
|
|
29
|
+
if (err instanceof ConnectError) {
|
|
30
|
+
return !code || err.code === code
|
|
31
|
+
}
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const authWithApiKey =
|
|
36
|
+
(apiKey: string): Interceptor =>
|
|
37
|
+
(next) =>
|
|
38
|
+
(req) => {
|
|
39
|
+
req.header.set('authorization', `Bearer ${apiKey}`)
|
|
40
|
+
return next(req)
|
|
41
|
+
}
|
|
@@ -30,6 +30,7 @@ import * as algo from './tables/algo'
|
|
|
30
30
|
import * as viewParam from './tables/view-param'
|
|
31
31
|
import * as suggestedFollow from './tables/suggested-follow'
|
|
32
32
|
import * as suggestedFeed from './tables/suggested-feed'
|
|
33
|
+
import * as taggedSuggestion from './tables/tagged-suggestion'
|
|
33
34
|
import * as blobTakedown from './tables/blob-takedown'
|
|
34
35
|
|
|
35
36
|
export type DatabaseSchemaType = duplicateRecord.PartialDB &
|
|
@@ -63,6 +64,7 @@ export type DatabaseSchemaType = duplicateRecord.PartialDB &
|
|
|
63
64
|
viewParam.PartialDB &
|
|
64
65
|
suggestedFollow.PartialDB &
|
|
65
66
|
suggestedFeed.PartialDB &
|
|
67
|
+
taggedSuggestion.PartialDB &
|
|
66
68
|
blobTakedown.PartialDB
|
|
67
69
|
|
|
68
70
|
export type DatabaseSchema = Kysely<DatabaseSchemaType>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Kysely } from 'kysely'
|
|
2
|
+
|
|
3
|
+
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
4
|
+
await db.schema
|
|
5
|
+
.createTable('tagged_suggestion')
|
|
6
|
+
.addColumn('tag', 'varchar', (col) => col.notNull())
|
|
7
|
+
.addColumn('subject', 'varchar', (col) => col.notNull())
|
|
8
|
+
.addColumn('subjectType', 'varchar', (col) => col.notNull())
|
|
9
|
+
.addPrimaryKeyConstraint('tagged_suggestion_pkey', ['tag', 'subject'])
|
|
10
|
+
.execute()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
14
|
+
await db.schema.dropTable('tagged_suggestion').execute()
|
|
15
|
+
}
|
|
@@ -33,3 +33,4 @@ export * as _20230929T192920807Z from './20230929T192920807Z-record-cursor-index
|
|
|
33
33
|
export * as _20231003T202833377Z from './20231003T202833377Z-create-moderation-subject-status'
|
|
34
34
|
export * as _20231205T000257238Z from './20231205T000257238Z-remove-did-cache'
|
|
35
35
|
export * as _20231220T225126090Z from './20231220T225126090Z-blob-takedowns'
|
|
36
|
+
export * as _20240124T023719200Z from './20240124T023719200Z-tagged-suggestions'
|
package/src/index.ts
CHANGED
|
@@ -29,11 +29,12 @@ import {
|
|
|
29
29
|
} from './image/invalidator'
|
|
30
30
|
import { BackgroundQueue } from './background'
|
|
31
31
|
import { MountedAlgos } from './feed-gen/types'
|
|
32
|
-
import { NotificationServer } from './notifications'
|
|
33
32
|
import { AtpAgent } from '@atproto/api'
|
|
34
33
|
import { Keypair } from '@atproto/crypto'
|
|
35
34
|
import { Redis } from './redis'
|
|
36
35
|
import { AuthVerifier } from './auth-verifier'
|
|
36
|
+
import { authWithApiKey as bsyncAuth, createBsyncClient } from './bsync'
|
|
37
|
+
import { authWithApiKey as courierAuth, createCourierClient } from './courier'
|
|
37
38
|
|
|
38
39
|
export type { ServerConfigValues } from './config'
|
|
39
40
|
export type { MountedAlgos } from './feed-gen/types'
|
|
@@ -112,7 +113,6 @@ export class BskyAppView {
|
|
|
112
113
|
|
|
113
114
|
const backgroundQueue = new BackgroundQueue(db.getPrimary())
|
|
114
115
|
|
|
115
|
-
const notifServer = new NotificationServer(db.getPrimary())
|
|
116
116
|
const searchAgent = config.searchEndpoint
|
|
117
117
|
? new AtpAgent({ service: config.searchEndpoint })
|
|
118
118
|
: undefined
|
|
@@ -135,6 +135,28 @@ export class BskyAppView {
|
|
|
135
135
|
triagePass: config.triagePassword,
|
|
136
136
|
})
|
|
137
137
|
|
|
138
|
+
const bsyncClient = config.bsyncUrl
|
|
139
|
+
? createBsyncClient({
|
|
140
|
+
baseUrl: config.bsyncUrl,
|
|
141
|
+
httpVersion: config.bsyncHttpVersion ?? '2',
|
|
142
|
+
nodeOptions: { rejectUnauthorized: !config.bsyncIgnoreBadTls },
|
|
143
|
+
interceptors: config.bsyncApiKey
|
|
144
|
+
? [bsyncAuth(config.bsyncApiKey)]
|
|
145
|
+
: [],
|
|
146
|
+
})
|
|
147
|
+
: undefined
|
|
148
|
+
|
|
149
|
+
const courierClient = config.courierUrl
|
|
150
|
+
? createCourierClient({
|
|
151
|
+
baseUrl: config.courierUrl,
|
|
152
|
+
httpVersion: config.courierHttpVersion ?? '2',
|
|
153
|
+
nodeOptions: { rejectUnauthorized: !config.courierIgnoreBadTls },
|
|
154
|
+
interceptors: config.courierApiKey
|
|
155
|
+
? [courierAuth(config.courierApiKey)]
|
|
156
|
+
: [],
|
|
157
|
+
})
|
|
158
|
+
: undefined
|
|
159
|
+
|
|
138
160
|
const ctx = new AppContext({
|
|
139
161
|
db,
|
|
140
162
|
cfg: config,
|
|
@@ -146,8 +168,9 @@ export class BskyAppView {
|
|
|
146
168
|
redis,
|
|
147
169
|
backgroundQueue,
|
|
148
170
|
searchAgent,
|
|
171
|
+
bsyncClient,
|
|
172
|
+
courierClient,
|
|
149
173
|
algos,
|
|
150
|
-
notifServer,
|
|
151
174
|
authVerifier,
|
|
152
175
|
})
|
|
153
176
|
|
package/src/indexer/config.ts
CHANGED
|
@@ -22,6 +22,10 @@ export interface IndexerConfigValues {
|
|
|
22
22
|
fuzzyFalsePositiveB64?: string
|
|
23
23
|
labelerKeywords: Record<string, string>
|
|
24
24
|
moderationPushUrl: string
|
|
25
|
+
courierUrl?: string
|
|
26
|
+
courierApiKey?: string
|
|
27
|
+
courierHttpVersion?: '1.1' | '2'
|
|
28
|
+
courierIgnoreBadTls?: boolean
|
|
25
29
|
indexerConcurrency?: number
|
|
26
30
|
indexerPartitionIds: number[]
|
|
27
31
|
indexerPartitionBatchSize?: number
|
|
@@ -72,6 +76,18 @@ export class IndexerConfig {
|
|
|
72
76
|
process.env.MODERATION_PUSH_URL ||
|
|
73
77
|
undefined
|
|
74
78
|
assert(moderationPushUrl)
|
|
79
|
+
const courierUrl =
|
|
80
|
+
overrides?.courierUrl || process.env.BSKY_COURIER_URL || undefined
|
|
81
|
+
const courierApiKey =
|
|
82
|
+
overrides?.courierApiKey || process.env.BSKY_COURIER_API_KEY || undefined
|
|
83
|
+
const courierHttpVersion =
|
|
84
|
+
overrides?.courierHttpVersion ||
|
|
85
|
+
process.env.BSKY_COURIER_HTTP_VERSION ||
|
|
86
|
+
'2'
|
|
87
|
+
const courierIgnoreBadTls =
|
|
88
|
+
overrides?.courierIgnoreBadTls ||
|
|
89
|
+
process.env.BSKY_COURIER_IGNORE_BAD_TLS === 'true'
|
|
90
|
+
assert(courierHttpVersion === '1.1' || courierHttpVersion === '2')
|
|
75
91
|
const hiveApiKey = process.env.HIVE_API_KEY || undefined
|
|
76
92
|
const abyssEndpoint = process.env.ABYSS_ENDPOINT
|
|
77
93
|
const abyssPassword = process.env.ABYSS_PASSWORD
|
|
@@ -114,6 +130,10 @@ export class IndexerConfig {
|
|
|
114
130
|
didCacheMaxTTL,
|
|
115
131
|
handleResolveNameservers,
|
|
116
132
|
moderationPushUrl,
|
|
133
|
+
courierUrl,
|
|
134
|
+
courierApiKey,
|
|
135
|
+
courierHttpVersion,
|
|
136
|
+
courierIgnoreBadTls,
|
|
117
137
|
hiveApiKey,
|
|
118
138
|
abyssEndpoint,
|
|
119
139
|
abyssPassword,
|
|
@@ -185,6 +205,22 @@ export class IndexerConfig {
|
|
|
185
205
|
return this.cfg.moderationPushUrl
|
|
186
206
|
}
|
|
187
207
|
|
|
208
|
+
get courierUrl() {
|
|
209
|
+
return this.cfg.courierUrl
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
get courierApiKey() {
|
|
213
|
+
return this.cfg.courierApiKey
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
get courierHttpVersion() {
|
|
217
|
+
return this.cfg.courierHttpVersion
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
get courierIgnoreBadTls() {
|
|
221
|
+
return this.cfg.courierIgnoreBadTls
|
|
222
|
+
}
|
|
223
|
+
|
|
188
224
|
get hiveApiKey() {
|
|
189
225
|
return this.cfg.hiveApiKey
|
|
190
226
|
}
|
package/src/indexer/context.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { BackgroundQueue } from '../background'
|
|
|
6
6
|
import DidSqlCache from '../did-cache'
|
|
7
7
|
import { Redis } from '../redis'
|
|
8
8
|
import { AutoModerator } from '../auto-moderator'
|
|
9
|
+
import { NotificationServer } from '../notifications'
|
|
9
10
|
|
|
10
11
|
export class IndexerContext {
|
|
11
12
|
constructor(
|
|
@@ -19,6 +20,7 @@ export class IndexerContext {
|
|
|
19
20
|
didCache: DidSqlCache
|
|
20
21
|
backgroundQueue: BackgroundQueue
|
|
21
22
|
autoMod: AutoModerator
|
|
23
|
+
notifServer?: NotificationServer
|
|
22
24
|
},
|
|
23
25
|
) {}
|
|
24
26
|
|
|
@@ -57,6 +59,10 @@ export class IndexerContext {
|
|
|
57
59
|
get autoMod(): AutoModerator {
|
|
58
60
|
return this.opts.autoMod
|
|
59
61
|
}
|
|
62
|
+
|
|
63
|
+
get notifServer(): NotificationServer | undefined {
|
|
64
|
+
return this.opts.notifServer
|
|
65
|
+
}
|
|
60
66
|
}
|
|
61
67
|
|
|
62
68
|
export default IndexerContext
|
package/src/indexer/index.ts
CHANGED
|
@@ -11,8 +11,13 @@ import { createServices } from './services'
|
|
|
11
11
|
import { IndexerSubscription } from './subscription'
|
|
12
12
|
import { AutoModerator } from '../auto-moderator'
|
|
13
13
|
import { Redis } from '../redis'
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
CourierNotificationServer,
|
|
16
|
+
GorushNotificationServer,
|
|
17
|
+
NotificationServer,
|
|
18
|
+
} from '../notifications'
|
|
15
19
|
import { CloseFn, createServer, startServer } from './server'
|
|
20
|
+
import { authWithApiKey as courierAuth, createCourierClient } from '../courier'
|
|
16
21
|
|
|
17
22
|
export { IndexerConfig } from './config'
|
|
18
23
|
export type { IndexerConfigValues } from './config'
|
|
@@ -60,9 +65,27 @@ export class BskyIndexer {
|
|
|
60
65
|
backgroundQueue,
|
|
61
66
|
})
|
|
62
67
|
|
|
63
|
-
const
|
|
64
|
-
?
|
|
68
|
+
const courierClient = cfg.courierUrl
|
|
69
|
+
? createCourierClient({
|
|
70
|
+
baseUrl: cfg.courierUrl,
|
|
71
|
+
httpVersion: cfg.courierHttpVersion ?? '2',
|
|
72
|
+
nodeOptions: { rejectUnauthorized: !cfg.courierIgnoreBadTls },
|
|
73
|
+
interceptors: cfg.courierApiKey
|
|
74
|
+
? [courierAuth(cfg.courierApiKey)]
|
|
75
|
+
: [],
|
|
76
|
+
})
|
|
65
77
|
: undefined
|
|
78
|
+
|
|
79
|
+
let notifServer: NotificationServer | undefined
|
|
80
|
+
if (courierClient) {
|
|
81
|
+
notifServer = new CourierNotificationServer(db, courierClient)
|
|
82
|
+
} else if (cfg.pushNotificationEndpoint) {
|
|
83
|
+
notifServer = new GorushNotificationServer(
|
|
84
|
+
db,
|
|
85
|
+
cfg.pushNotificationEndpoint,
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
66
89
|
const services = createServices({
|
|
67
90
|
idResolver,
|
|
68
91
|
autoMod,
|
|
@@ -79,6 +102,7 @@ export class BskyIndexer {
|
|
|
79
102
|
didCache,
|
|
80
103
|
backgroundQueue,
|
|
81
104
|
autoMod,
|
|
105
|
+
notifServer,
|
|
82
106
|
})
|
|
83
107
|
const sub = new IndexerSubscription(ctx, {
|
|
84
108
|
partitionIds: cfg.indexerPartitionIds,
|
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)
|