@atproto/bsky 0.0.13 → 0.0.15
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 +18 -0
- package/dist/api/app/bsky/feed/searchPosts.d.ts +3 -0
- package/dist/api/com/atproto/temp/fetchLabels.d.ts +3 -0
- package/dist/config.d.ts +2 -2
- package/dist/context.d.ts +1 -1
- package/dist/index.js +723 -443
- package/dist/index.js.map +3 -3
- package/dist/lexicon/index.d.ts +7 -0
- package/dist/lexicon/lexicons.d.ts +63 -0
- package/dist/lexicon/types/com/atproto/admin/defs.d.ts +2 -0
- package/dist/lexicon/types/com/atproto/server/getSession.d.ts +1 -0
- package/dist/lexicon/types/com/atproto/temp/fetchLabels.d.ts +33 -0
- package/package.json +10 -11
- package/src/api/app/bsky/actor/getSuggestions.ts +45 -21
- package/src/api/app/bsky/feed/getPostThread.ts +16 -4
- package/src/api/app/bsky/feed/searchPosts.ts +127 -0
- package/src/api/com/atproto/admin/reverseModerationAction.ts +3 -3
- package/src/api/com/atproto/admin/takeModerationAction.ts +2 -2
- package/src/api/com/atproto/admin/util.ts +3 -1
- package/src/api/com/atproto/temp/fetchLabels.ts +30 -0
- package/src/api/index.ts +4 -0
- package/src/config.ts +6 -6
- package/src/context.ts +11 -9
- package/src/db/periodic-moderation-action-reversal.ts +1 -9
- package/src/lexicon/index.ts +22 -0
- package/src/lexicon/lexicons.ts +192 -129
- package/src/lexicon/types/app/bsky/actor/defs.ts +2 -2
- package/src/lexicon/types/app/bsky/actor/searchActors.ts +2 -2
- package/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts +2 -2
- package/src/lexicon/types/app/bsky/feed/searchPosts.ts +3 -3
- package/src/lexicon/types/app/bsky/graph/defs.ts +2 -2
- package/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts +4 -4
- package/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts +3 -3
- package/src/lexicon/types/com/atproto/admin/defs.ts +5 -3
- package/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts +1 -1
- package/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts +1 -1
- package/src/lexicon/types/com/atproto/admin/getModerationReports.ts +3 -3
- package/src/lexicon/types/com/atproto/admin/takeModerationAction.ts +1 -1
- package/src/lexicon/types/com/atproto/label/defs.ts +9 -9
- package/src/lexicon/types/com/atproto/label/queryLabels.ts +2 -2
- package/src/lexicon/types/com/atproto/repo/applyWrites.ts +1 -1
- package/src/lexicon/types/com/atproto/repo/createRecord.ts +2 -2
- package/src/lexicon/types/com/atproto/repo/deleteRecord.ts +2 -2
- package/src/lexicon/types/com/atproto/repo/listRecords.ts +1 -1
- package/src/lexicon/types/com/atproto/repo/putRecord.ts +3 -3
- package/src/lexicon/types/com/atproto/server/getSession.ts +1 -0
- package/src/lexicon/types/com/atproto/sync/listBlobs.ts +1 -1
- package/src/lexicon/types/com/atproto/sync/subscribeRepos.ts +4 -4
- package/src/lexicon/types/com/atproto/temp/fetchLabels.ts +47 -0
- package/tests/admin/get-repo.test.ts +33 -0
- package/tests/views/suggestions.test.ts +15 -7
package/dist/lexicon/index.d.ts
CHANGED
|
@@ -65,6 +65,7 @@ import * as ComAtprotoSyncListRepos from './types/com/atproto/sync/listRepos';
|
|
|
65
65
|
import * as ComAtprotoSyncNotifyOfUpdate from './types/com/atproto/sync/notifyOfUpdate';
|
|
66
66
|
import * as ComAtprotoSyncRequestCrawl from './types/com/atproto/sync/requestCrawl';
|
|
67
67
|
import * as ComAtprotoSyncSubscribeRepos from './types/com/atproto/sync/subscribeRepos';
|
|
68
|
+
import * as ComAtprotoTempFetchLabels from './types/com/atproto/temp/fetchLabels';
|
|
68
69
|
import * as AppBskyActorGetPreferences from './types/app/bsky/actor/getPreferences';
|
|
69
70
|
import * as AppBskyActorGetProfile from './types/app/bsky/actor/getProfile';
|
|
70
71
|
import * as AppBskyActorGetProfiles from './types/app/bsky/actor/getProfiles';
|
|
@@ -149,6 +150,7 @@ export declare class AtprotoNS {
|
|
|
149
150
|
repo: RepoNS;
|
|
150
151
|
server: ServerNS;
|
|
151
152
|
sync: SyncNS;
|
|
153
|
+
temp: TempNS;
|
|
152
154
|
constructor(server: Server);
|
|
153
155
|
}
|
|
154
156
|
export declare class AdminNS {
|
|
@@ -245,6 +247,11 @@ export declare class SyncNS {
|
|
|
245
247
|
requestCrawl<AV extends AuthVerifier>(cfg: ConfigOf<AV, ComAtprotoSyncRequestCrawl.Handler<ExtractAuth<AV>>, ComAtprotoSyncRequestCrawl.HandlerReqCtx<ExtractAuth<AV>>>): void;
|
|
246
248
|
subscribeRepos<AV extends StreamAuthVerifier>(cfg: ConfigOf<AV, ComAtprotoSyncSubscribeRepos.Handler<ExtractAuth<AV>>, ComAtprotoSyncSubscribeRepos.HandlerReqCtx<ExtractAuth<AV>>>): void;
|
|
247
249
|
}
|
|
250
|
+
export declare class TempNS {
|
|
251
|
+
_server: Server;
|
|
252
|
+
constructor(server: Server);
|
|
253
|
+
fetchLabels<AV extends AuthVerifier>(cfg: ConfigOf<AV, ComAtprotoTempFetchLabels.Handler<ExtractAuth<AV>>, ComAtprotoTempFetchLabels.HandlerReqCtx<ExtractAuth<AV>>>): void;
|
|
254
|
+
}
|
|
248
255
|
export declare class AppNS {
|
|
249
256
|
_server: Server;
|
|
250
257
|
bsky: BskyNS;
|
|
@@ -358,6 +358,10 @@ export declare const schemaDict: {
|
|
|
358
358
|
inviteNote: {
|
|
359
359
|
type: string;
|
|
360
360
|
};
|
|
361
|
+
emailConfirmedAt: {
|
|
362
|
+
type: string;
|
|
363
|
+
format: string;
|
|
364
|
+
};
|
|
361
365
|
};
|
|
362
366
|
};
|
|
363
367
|
accountView: {
|
|
@@ -393,6 +397,10 @@ export declare const schemaDict: {
|
|
|
393
397
|
invitesDisabled: {
|
|
394
398
|
type: string;
|
|
395
399
|
};
|
|
400
|
+
emailConfirmedAt: {
|
|
401
|
+
type: string;
|
|
402
|
+
format: string;
|
|
403
|
+
};
|
|
396
404
|
inviteNote: {
|
|
397
405
|
type: string;
|
|
398
406
|
};
|
|
@@ -2758,6 +2766,9 @@ export declare const schemaDict: {
|
|
|
2758
2766
|
emailConfirmed: {
|
|
2759
2767
|
type: string;
|
|
2760
2768
|
};
|
|
2769
|
+
didDoc: {
|
|
2770
|
+
type: string;
|
|
2771
|
+
};
|
|
2761
2772
|
};
|
|
2762
2773
|
};
|
|
2763
2774
|
};
|
|
@@ -3582,6 +3593,46 @@ export declare const schemaDict: {
|
|
|
3582
3593
|
};
|
|
3583
3594
|
};
|
|
3584
3595
|
};
|
|
3596
|
+
ComAtprotoTempFetchLabels: {
|
|
3597
|
+
lexicon: number;
|
|
3598
|
+
id: string;
|
|
3599
|
+
defs: {
|
|
3600
|
+
main: {
|
|
3601
|
+
type: string;
|
|
3602
|
+
description: string;
|
|
3603
|
+
parameters: {
|
|
3604
|
+
type: string;
|
|
3605
|
+
properties: {
|
|
3606
|
+
since: {
|
|
3607
|
+
type: string;
|
|
3608
|
+
};
|
|
3609
|
+
limit: {
|
|
3610
|
+
type: string;
|
|
3611
|
+
minimum: number;
|
|
3612
|
+
maximum: number;
|
|
3613
|
+
default: number;
|
|
3614
|
+
};
|
|
3615
|
+
};
|
|
3616
|
+
};
|
|
3617
|
+
output: {
|
|
3618
|
+
encoding: string;
|
|
3619
|
+
schema: {
|
|
3620
|
+
type: string;
|
|
3621
|
+
required: string[];
|
|
3622
|
+
properties: {
|
|
3623
|
+
labels: {
|
|
3624
|
+
type: string;
|
|
3625
|
+
items: {
|
|
3626
|
+
type: string;
|
|
3627
|
+
ref: string;
|
|
3628
|
+
};
|
|
3629
|
+
};
|
|
3630
|
+
};
|
|
3631
|
+
};
|
|
3632
|
+
};
|
|
3633
|
+
};
|
|
3634
|
+
};
|
|
3635
|
+
};
|
|
3585
3636
|
AppBskyActorDefs: {
|
|
3586
3637
|
lexicon: number;
|
|
3587
3638
|
id: string;
|
|
@@ -3886,6 +3937,7 @@ export declare const schemaDict: {
|
|
|
3886
3937
|
defs: {
|
|
3887
3938
|
main: {
|
|
3888
3939
|
type: string;
|
|
3940
|
+
description: string;
|
|
3889
3941
|
parameters: {
|
|
3890
3942
|
type: string;
|
|
3891
3943
|
required: string[];
|
|
@@ -3912,6 +3964,7 @@ export declare const schemaDict: {
|
|
|
3912
3964
|
defs: {
|
|
3913
3965
|
main: {
|
|
3914
3966
|
type: string;
|
|
3967
|
+
description: string;
|
|
3915
3968
|
parameters: {
|
|
3916
3969
|
type: string;
|
|
3917
3970
|
required: string[];
|
|
@@ -3994,6 +4047,7 @@ export declare const schemaDict: {
|
|
|
3994
4047
|
defs: {
|
|
3995
4048
|
main: {
|
|
3996
4049
|
type: string;
|
|
4050
|
+
description: string;
|
|
3997
4051
|
key: string;
|
|
3998
4052
|
record: {
|
|
3999
4053
|
type: string;
|
|
@@ -5185,6 +5239,7 @@ export declare const schemaDict: {
|
|
|
5185
5239
|
defs: {
|
|
5186
5240
|
main: {
|
|
5187
5241
|
type: string;
|
|
5242
|
+
description: string;
|
|
5188
5243
|
parameters: {
|
|
5189
5244
|
type: string;
|
|
5190
5245
|
required: string[];
|
|
@@ -5313,6 +5368,7 @@ export declare const schemaDict: {
|
|
|
5313
5368
|
defs: {
|
|
5314
5369
|
main: {
|
|
5315
5370
|
type: string;
|
|
5371
|
+
description: string;
|
|
5316
5372
|
parameters: {
|
|
5317
5373
|
type: string;
|
|
5318
5374
|
required: string[];
|
|
@@ -5400,6 +5456,7 @@ export declare const schemaDict: {
|
|
|
5400
5456
|
defs: {
|
|
5401
5457
|
main: {
|
|
5402
5458
|
type: string;
|
|
5459
|
+
description: string;
|
|
5403
5460
|
parameters: {
|
|
5404
5461
|
type: string;
|
|
5405
5462
|
required: string[];
|
|
@@ -5548,6 +5605,7 @@ export declare const schemaDict: {
|
|
|
5548
5605
|
defs: {
|
|
5549
5606
|
main: {
|
|
5550
5607
|
type: string;
|
|
5608
|
+
description: string;
|
|
5551
5609
|
key: string;
|
|
5552
5610
|
record: {
|
|
5553
5611
|
type: string;
|
|
@@ -5572,6 +5630,7 @@ export declare const schemaDict: {
|
|
|
5572
5630
|
defs: {
|
|
5573
5631
|
main: {
|
|
5574
5632
|
type: string;
|
|
5633
|
+
description: string;
|
|
5575
5634
|
key: string;
|
|
5576
5635
|
record: {
|
|
5577
5636
|
type: string;
|
|
@@ -5688,6 +5747,7 @@ export declare const schemaDict: {
|
|
|
5688
5747
|
id: string;
|
|
5689
5748
|
defs: {
|
|
5690
5749
|
main: {
|
|
5750
|
+
description: string;
|
|
5691
5751
|
type: string;
|
|
5692
5752
|
key: string;
|
|
5693
5753
|
record: {
|
|
@@ -6606,6 +6666,7 @@ export declare const schemaDict: {
|
|
|
6606
6666
|
defs: {
|
|
6607
6667
|
main: {
|
|
6608
6668
|
type: string;
|
|
6669
|
+
description: string;
|
|
6609
6670
|
parameters: {
|
|
6610
6671
|
type: string;
|
|
6611
6672
|
properties: {
|
|
@@ -6636,6 +6697,7 @@ export declare const schemaDict: {
|
|
|
6636
6697
|
defs: {
|
|
6637
6698
|
main: {
|
|
6638
6699
|
type: string;
|
|
6700
|
+
description: string;
|
|
6639
6701
|
parameters: {
|
|
6640
6702
|
type: string;
|
|
6641
6703
|
properties: {
|
|
@@ -7204,6 +7266,7 @@ export declare const ids: {
|
|
|
7204
7266
|
ComAtprotoSyncNotifyOfUpdate: string;
|
|
7205
7267
|
ComAtprotoSyncRequestCrawl: string;
|
|
7206
7268
|
ComAtprotoSyncSubscribeRepos: string;
|
|
7269
|
+
ComAtprotoTempFetchLabels: string;
|
|
7207
7270
|
AppBskyActorDefs: string;
|
|
7208
7271
|
AppBskyActorGetPreferences: string;
|
|
7209
7272
|
AppBskyActorGetProfile: string;
|
|
@@ -128,6 +128,7 @@ export interface RepoViewDetail {
|
|
|
128
128
|
invites?: ComAtprotoServerDefs.InviteCode[];
|
|
129
129
|
invitesDisabled?: boolean;
|
|
130
130
|
inviteNote?: string;
|
|
131
|
+
emailConfirmedAt?: string;
|
|
131
132
|
[k: string]: unknown;
|
|
132
133
|
}
|
|
133
134
|
export declare function isRepoViewDetail(v: unknown): v is RepoViewDetail;
|
|
@@ -140,6 +141,7 @@ export interface AccountView {
|
|
|
140
141
|
invitedBy?: ComAtprotoServerDefs.InviteCode;
|
|
141
142
|
invites?: ComAtprotoServerDefs.InviteCode[];
|
|
142
143
|
invitesDisabled?: boolean;
|
|
144
|
+
emailConfirmedAt?: string;
|
|
143
145
|
inviteNote?: string;
|
|
144
146
|
[k: string]: unknown;
|
|
145
147
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { HandlerAuth } from '@atproto/xrpc-server';
|
|
3
|
+
import * as ComAtprotoLabelDefs from '../label/defs';
|
|
4
|
+
export interface QueryParams {
|
|
5
|
+
since?: number;
|
|
6
|
+
limit: number;
|
|
7
|
+
}
|
|
8
|
+
export declare type InputSchema = undefined;
|
|
9
|
+
export interface OutputSchema {
|
|
10
|
+
labels: ComAtprotoLabelDefs.Label[];
|
|
11
|
+
[k: string]: unknown;
|
|
12
|
+
}
|
|
13
|
+
export declare type HandlerInput = undefined;
|
|
14
|
+
export interface HandlerSuccess {
|
|
15
|
+
encoding: 'application/json';
|
|
16
|
+
body: OutputSchema;
|
|
17
|
+
headers?: {
|
|
18
|
+
[key: string]: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface HandlerError {
|
|
22
|
+
status: number;
|
|
23
|
+
message?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare type HandlerOutput = HandlerError | HandlerSuccess;
|
|
26
|
+
export declare type HandlerReqCtx<HA extends HandlerAuth = never> = {
|
|
27
|
+
auth: HA;
|
|
28
|
+
params: QueryParams;
|
|
29
|
+
input: HandlerInput;
|
|
30
|
+
req: express.Request;
|
|
31
|
+
res: express.Response;
|
|
32
|
+
};
|
|
33
|
+
export declare type Handler<HA extends HandlerAuth = never> = (ctx: HandlerReqCtx<HA>) => Promise<HandlerOutput> | HandlerOutput;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/bsky",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Reference implementation of app.bsky App View (Bluesky API)",
|
|
6
6
|
"keywords": [
|
|
@@ -32,17 +32,17 @@
|
|
|
32
32
|
"pg": "^8.10.0",
|
|
33
33
|
"pino": "^8.15.0",
|
|
34
34
|
"pino-http": "^8.2.1",
|
|
35
|
-
"sharp": "^0.
|
|
35
|
+
"sharp": "^0.32.6",
|
|
36
36
|
"typed-emitter": "^2.1.0",
|
|
37
37
|
"uint8arrays": "3.0.0",
|
|
38
|
-
"@atproto/api": "^0.6.
|
|
38
|
+
"@atproto/api": "^0.6.23",
|
|
39
39
|
"@atproto/common": "^0.3.3",
|
|
40
|
-
"@atproto/crypto": "^0.
|
|
40
|
+
"@atproto/crypto": "^0.3.0",
|
|
41
41
|
"@atproto/syntax": "^0.1.4",
|
|
42
|
-
"@atproto/identity": "^0.3.
|
|
42
|
+
"@atproto/identity": "^0.3.2",
|
|
43
43
|
"@atproto/lexicon": "^0.3.0",
|
|
44
|
-
"@atproto/repo": "^0.3.
|
|
45
|
-
"@atproto/xrpc-server": "^0.4.
|
|
44
|
+
"@atproto/repo": "^0.3.5",
|
|
45
|
+
"@atproto/xrpc-server": "^0.4.1"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@did-plc/server": "^0.0.1",
|
|
@@ -51,12 +51,11 @@
|
|
|
51
51
|
"@types/express-serve-static-core": "^4.17.36",
|
|
52
52
|
"@types/pg": "^8.6.6",
|
|
53
53
|
"@types/qs": "^6.9.7",
|
|
54
|
-
"@types/sharp": "^0.31.0",
|
|
55
54
|
"axios": "^0.27.2",
|
|
56
|
-
"@atproto/api": "^0.6.
|
|
57
|
-
"@atproto/dev-env": "^0.2.
|
|
55
|
+
"@atproto/api": "^0.6.23",
|
|
56
|
+
"@atproto/dev-env": "^0.2.15",
|
|
58
57
|
"@atproto/lex-cli": "^0.2.4",
|
|
59
|
-
"@atproto/pds": "^0.3.
|
|
58
|
+
"@atproto/pds": "^0.3.3",
|
|
60
59
|
"@atproto/xrpc": "^0.4.0"
|
|
61
60
|
},
|
|
62
61
|
"scripts": {
|
|
@@ -42,12 +42,12 @@ const skeleton = async (
|
|
|
42
42
|
ctx: Context,
|
|
43
43
|
): Promise<SkeletonState> => {
|
|
44
44
|
const { db } = ctx
|
|
45
|
-
const {
|
|
45
|
+
const { viewer } = params
|
|
46
|
+
const alreadyIncluded = parseCursor(params.cursor)
|
|
46
47
|
const { ref } = db.db.dynamic
|
|
47
|
-
|
|
48
|
+
const suggestions = await db.db
|
|
48
49
|
.selectFrom('suggested_follow')
|
|
49
50
|
.innerJoin('actor', 'actor.did', 'suggested_follow.did')
|
|
50
|
-
.innerJoin('profile_agg', 'profile_agg.did', 'actor.did')
|
|
51
51
|
.where(notSoftDeletedClause(ref('actor')))
|
|
52
52
|
.where('suggested_follow.did', '!=', viewer ?? '')
|
|
53
53
|
.whereNotExists((qb) =>
|
|
@@ -57,27 +57,30 @@ const skeleton = async (
|
|
|
57
57
|
.where('creator', '=', viewer ?? '')
|
|
58
58
|
.whereRef('subjectDid', '=', ref('actor.did')),
|
|
59
59
|
)
|
|
60
|
+
.if(alreadyIncluded.length > 0, (qb) =>
|
|
61
|
+
qb.where('suggested_follow.order', 'not in', alreadyIncluded),
|
|
62
|
+
)
|
|
60
63
|
.selectAll()
|
|
61
|
-
.select('profile_agg.postsCount as postsCount')
|
|
62
|
-
.limit(limit)
|
|
63
64
|
.orderBy('suggested_follow.order', 'asc')
|
|
65
|
+
.execute()
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
67
|
+
// always include first two
|
|
68
|
+
const firstTwo = suggestions.filter(
|
|
69
|
+
(row) => row.order === 1 || row.order === 2,
|
|
70
|
+
)
|
|
71
|
+
const rest = suggestions.filter((row) => row.order !== 1 && row.order !== 2)
|
|
72
|
+
const limited = firstTwo.concat(shuffle(rest)).slice(0, params.limit)
|
|
73
|
+
|
|
74
|
+
// if the result set ends up getting larger, consider using a seed included in the cursor for for the randomized shuffle
|
|
75
|
+
const cursor =
|
|
76
|
+
limited.length > 0
|
|
77
|
+
? limited
|
|
78
|
+
.map((row) => row.order.toString())
|
|
79
|
+
.concat(alreadyIncluded.map((id) => id.toString()))
|
|
80
|
+
.join(':')
|
|
81
|
+
: undefined
|
|
82
|
+
|
|
83
|
+
return { params, suggestions: limited, cursor }
|
|
81
84
|
}
|
|
82
85
|
|
|
83
86
|
const hydration = async (state: SkeletonState, ctx: Context) => {
|
|
@@ -110,6 +113,27 @@ const presentation = (state: HydrationState) => {
|
|
|
110
113
|
return { actors: suggestedActors, cursor }
|
|
111
114
|
}
|
|
112
115
|
|
|
116
|
+
const parseCursor = (cursor?: string): number[] => {
|
|
117
|
+
if (!cursor) {
|
|
118
|
+
return []
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
return cursor
|
|
122
|
+
.split(':')
|
|
123
|
+
.map((id) => parseInt(id, 10))
|
|
124
|
+
.filter((id) => !isNaN(id))
|
|
125
|
+
} catch {
|
|
126
|
+
return []
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const shuffle = <T>(arr: T[]): T[] => {
|
|
131
|
+
return arr
|
|
132
|
+
.map((value) => ({ value, sort: Math.random() }))
|
|
133
|
+
.sort((a, b) => a.sort - b.sort)
|
|
134
|
+
.map(({ value }) => value)
|
|
135
|
+
}
|
|
136
|
+
|
|
113
137
|
type Context = {
|
|
114
138
|
db: Database
|
|
115
139
|
actorService: ActorService
|
|
@@ -255,11 +255,15 @@ const getThreadData = async (
|
|
|
255
255
|
.orderBy('sortAt', 'desc')
|
|
256
256
|
.execute(),
|
|
257
257
|
])
|
|
258
|
-
|
|
259
|
-
|
|
258
|
+
// prevent self-referential loops
|
|
259
|
+
const includedPosts = new Set<string>([uri])
|
|
260
|
+
const parentsByUri = parents.reduce((acc, post) => {
|
|
261
|
+
return Object.assign(acc, { [post.uri]: post })
|
|
260
262
|
}, {} as Record<string, FeedRow>)
|
|
261
263
|
const childrenByParentUri = children.reduce((acc, child) => {
|
|
262
264
|
if (!child.replyParent) return acc
|
|
265
|
+
if (includedPosts.has(child.uri)) return acc
|
|
266
|
+
includedPosts.add(child.uri)
|
|
263
267
|
acc[child.replyParent] ??= []
|
|
264
268
|
acc[child.replyParent].push(child)
|
|
265
269
|
return acc
|
|
@@ -269,7 +273,12 @@ const getThreadData = async (
|
|
|
269
273
|
return {
|
|
270
274
|
post,
|
|
271
275
|
parent: post.replyParent
|
|
272
|
-
? getParentData(
|
|
276
|
+
? getParentData(
|
|
277
|
+
parentsByUri,
|
|
278
|
+
includedPosts,
|
|
279
|
+
post.replyParent,
|
|
280
|
+
parentHeight,
|
|
281
|
+
)
|
|
273
282
|
: undefined,
|
|
274
283
|
replies: getChildrenData(childrenByParentUri, uri, depth),
|
|
275
284
|
}
|
|
@@ -277,16 +286,19 @@ const getThreadData = async (
|
|
|
277
286
|
|
|
278
287
|
const getParentData = (
|
|
279
288
|
postsByUri: Record<string, FeedRow>,
|
|
289
|
+
includedPosts: Set<string>,
|
|
280
290
|
uri: string,
|
|
281
291
|
depth: number,
|
|
282
292
|
): PostThread | ParentNotFoundError | undefined => {
|
|
283
293
|
if (depth < 1) return undefined
|
|
294
|
+
if (includedPosts.has(uri)) return undefined
|
|
295
|
+
includedPosts.add(uri)
|
|
284
296
|
const post = postsByUri[uri]
|
|
285
297
|
if (!post) return new ParentNotFoundError(uri)
|
|
286
298
|
return {
|
|
287
299
|
post,
|
|
288
300
|
parent: post.replyParent
|
|
289
|
-
? getParentData(postsByUri, post.replyParent, depth - 1)
|
|
301
|
+
? getParentData(postsByUri, includedPosts, post.replyParent, depth - 1)
|
|
290
302
|
: undefined,
|
|
291
303
|
replies: [],
|
|
292
304
|
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import AppContext from '../../../../context'
|
|
2
|
+
import { Server } from '../../../../lexicon'
|
|
3
|
+
import { InvalidRequestError } from '@atproto/xrpc-server'
|
|
4
|
+
import AtpAgent from '@atproto/api'
|
|
5
|
+
import { AtUri } from '@atproto/syntax'
|
|
6
|
+
import { mapDefined } from '@atproto/common'
|
|
7
|
+
import { QueryParams } from '../../../../lexicon/types/app/bsky/feed/searchPosts'
|
|
8
|
+
import { Database } from '../../../../db'
|
|
9
|
+
import { FeedHydrationState, FeedService } from '../../../../services/feed'
|
|
10
|
+
import { ActorService } from '../../../../services/actor'
|
|
11
|
+
import { createPipeline } from '../../../../pipeline'
|
|
12
|
+
|
|
13
|
+
export default function (server: Server, ctx: AppContext) {
|
|
14
|
+
const searchPosts = createPipeline(
|
|
15
|
+
skeleton,
|
|
16
|
+
hydration,
|
|
17
|
+
noBlocks,
|
|
18
|
+
presentation,
|
|
19
|
+
)
|
|
20
|
+
server.app.bsky.feed.searchPosts({
|
|
21
|
+
auth: ctx.authOptionalVerifier,
|
|
22
|
+
handler: async ({ auth, params }) => {
|
|
23
|
+
const viewer = auth.credentials.did
|
|
24
|
+
const db = ctx.db.getReplica('search')
|
|
25
|
+
const feedService = ctx.services.feed(db)
|
|
26
|
+
const actorService = ctx.services.actor(db)
|
|
27
|
+
const searchAgent = ctx.searchAgent
|
|
28
|
+
if (!searchAgent) {
|
|
29
|
+
throw new InvalidRequestError('Search not available')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const results = await searchPosts(
|
|
33
|
+
{ ...params, viewer },
|
|
34
|
+
{ db, feedService, actorService, searchAgent },
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
encoding: 'application/json',
|
|
39
|
+
body: results,
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const skeleton = async (
|
|
46
|
+
params: Params,
|
|
47
|
+
ctx: Context,
|
|
48
|
+
): Promise<SkeletonState> => {
|
|
49
|
+
const res = await ctx.searchAgent.api.app.bsky.unspecced.searchPostsSkeleton({
|
|
50
|
+
q: params.q,
|
|
51
|
+
cursor: params.cursor,
|
|
52
|
+
limit: params.limit,
|
|
53
|
+
})
|
|
54
|
+
return {
|
|
55
|
+
params,
|
|
56
|
+
postUris: res.data.posts.map((a) => a.uri),
|
|
57
|
+
cursor: res.data.cursor,
|
|
58
|
+
hitsTotal: res.data.hitsTotal,
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const hydration = async (
|
|
63
|
+
state: SkeletonState,
|
|
64
|
+
ctx: Context,
|
|
65
|
+
): Promise<HydrationState> => {
|
|
66
|
+
const { feedService } = ctx
|
|
67
|
+
const { params, postUris } = state
|
|
68
|
+
const uris = new Set<string>(postUris)
|
|
69
|
+
const dids = new Set<string>(postUris.map((uri) => new AtUri(uri).hostname))
|
|
70
|
+
const hydrated = await feedService.feedHydration({
|
|
71
|
+
uris,
|
|
72
|
+
dids,
|
|
73
|
+
viewer: params.viewer,
|
|
74
|
+
})
|
|
75
|
+
return { ...state, ...hydrated }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const noBlocks = (state: HydrationState): HydrationState => {
|
|
79
|
+
const { viewer } = state.params
|
|
80
|
+
state.postUris = state.postUris.filter((uri) => {
|
|
81
|
+
const post = state.posts[uri]
|
|
82
|
+
if (!viewer || !post) return true
|
|
83
|
+
return !state.bam.block([viewer, post.creator])
|
|
84
|
+
})
|
|
85
|
+
return state
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const presentation = (state: HydrationState, ctx: Context) => {
|
|
89
|
+
const { feedService, actorService } = ctx
|
|
90
|
+
const { postUris, profiles, params } = state
|
|
91
|
+
const actors = actorService.views.profileBasicPresentation(
|
|
92
|
+
Object.keys(profiles),
|
|
93
|
+
state,
|
|
94
|
+
{ viewer: params.viewer },
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
const postViews = mapDefined(postUris, (uri) =>
|
|
98
|
+
feedService.views.formatPostView(
|
|
99
|
+
uri,
|
|
100
|
+
actors,
|
|
101
|
+
state.posts,
|
|
102
|
+
state.threadgates,
|
|
103
|
+
state.embeds,
|
|
104
|
+
state.labels,
|
|
105
|
+
state.lists,
|
|
106
|
+
),
|
|
107
|
+
)
|
|
108
|
+
return { posts: postViews, cursor: state.cursor, hitsTotal: state.hitsTotal }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
type Context = {
|
|
112
|
+
db: Database
|
|
113
|
+
feedService: FeedService
|
|
114
|
+
actorService: ActorService
|
|
115
|
+
searchAgent: AtpAgent
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
type Params = QueryParams & { viewer: string | null }
|
|
119
|
+
|
|
120
|
+
type SkeletonState = {
|
|
121
|
+
params: Params
|
|
122
|
+
postUris: string[]
|
|
123
|
+
hitsTotal?: number
|
|
124
|
+
cursor?: string
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
type HydrationState = SkeletonState & FeedHydrationState
|
|
@@ -85,9 +85,9 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
85
85
|
return { result, restored }
|
|
86
86
|
})
|
|
87
87
|
|
|
88
|
-
if (restored) {
|
|
89
|
-
const
|
|
90
|
-
const
|
|
88
|
+
if (restored && ctx.moderationPushAgent) {
|
|
89
|
+
const agent = ctx.moderationPushAgent
|
|
90
|
+
const { subjects } = restored
|
|
91
91
|
const results = await Promise.allSettled(
|
|
92
92
|
subjects.map((subject) =>
|
|
93
93
|
retryHttp(() =>
|
|
@@ -111,10 +111,10 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
111
111
|
return { result, takenDown }
|
|
112
112
|
})
|
|
113
113
|
|
|
114
|
-
if (takenDown) {
|
|
114
|
+
if (takenDown && ctx.moderationPushAgent) {
|
|
115
|
+
const agent = ctx.moderationPushAgent
|
|
115
116
|
const { did, subjects } = takenDown
|
|
116
117
|
if (did && subjects.length > 0) {
|
|
117
|
-
const agent = await ctx.pdsAdminAgent(did)
|
|
118
118
|
const results = await Promise.allSettled(
|
|
119
119
|
subjects.map((subject) =>
|
|
120
120
|
retryHttp(() =>
|
|
@@ -9,8 +9,9 @@ export const getPdsAccountInfo = async (
|
|
|
9
9
|
ctx: AppContext,
|
|
10
10
|
did: string,
|
|
11
11
|
): Promise<AccountView | null> => {
|
|
12
|
+
const agent = ctx.moderationPushAgent
|
|
13
|
+
if (!agent) return null
|
|
12
14
|
try {
|
|
13
|
-
const agent = await ctx.pdsAdminAgent(did)
|
|
14
15
|
const res = await agent.api.com.atproto.admin.getAccountInfo({ did })
|
|
15
16
|
return res.data
|
|
16
17
|
} catch (err) {
|
|
@@ -31,6 +32,7 @@ export const addAccountInfoToRepoViewDetail = (
|
|
|
31
32
|
invitesDisabled: accountInfo.invitesDisabled,
|
|
32
33
|
inviteNote: accountInfo.inviteNote,
|
|
33
34
|
invites: accountInfo.invites,
|
|
35
|
+
emailConfirmedAt: accountInfo.emailConfirmedAt,
|
|
34
36
|
}
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Server } from '../../../../lexicon'
|
|
2
|
+
import AppContext from '../../../../context'
|
|
3
|
+
|
|
4
|
+
export default function (server: Server, ctx: AppContext) {
|
|
5
|
+
server.com.atproto.temp.fetchLabels(async ({ params }) => {
|
|
6
|
+
const { limit } = params
|
|
7
|
+
const db = ctx.db.getReplica()
|
|
8
|
+
const since =
|
|
9
|
+
params.since !== undefined ? new Date(params.since).toISOString() : ''
|
|
10
|
+
const labelRes = await db.db
|
|
11
|
+
.selectFrom('label')
|
|
12
|
+
.selectAll()
|
|
13
|
+
.orderBy('label.cts', 'asc')
|
|
14
|
+
.where('cts', '>', since)
|
|
15
|
+
.limit(limit)
|
|
16
|
+
.execute()
|
|
17
|
+
|
|
18
|
+
const labels = labelRes.map((l) => ({
|
|
19
|
+
...l,
|
|
20
|
+
cid: l.cid === '' ? undefined : l.cid,
|
|
21
|
+
}))
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
encoding: 'application/json',
|
|
25
|
+
body: {
|
|
26
|
+
labels,
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
}
|