@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.
Files changed (51) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/api/app/bsky/feed/searchPosts.d.ts +3 -0
  3. package/dist/api/com/atproto/temp/fetchLabels.d.ts +3 -0
  4. package/dist/config.d.ts +2 -2
  5. package/dist/context.d.ts +1 -1
  6. package/dist/index.js +723 -443
  7. package/dist/index.js.map +3 -3
  8. package/dist/lexicon/index.d.ts +7 -0
  9. package/dist/lexicon/lexicons.d.ts +63 -0
  10. package/dist/lexicon/types/com/atproto/admin/defs.d.ts +2 -0
  11. package/dist/lexicon/types/com/atproto/server/getSession.d.ts +1 -0
  12. package/dist/lexicon/types/com/atproto/temp/fetchLabels.d.ts +33 -0
  13. package/package.json +10 -11
  14. package/src/api/app/bsky/actor/getSuggestions.ts +45 -21
  15. package/src/api/app/bsky/feed/getPostThread.ts +16 -4
  16. package/src/api/app/bsky/feed/searchPosts.ts +127 -0
  17. package/src/api/com/atproto/admin/reverseModerationAction.ts +3 -3
  18. package/src/api/com/atproto/admin/takeModerationAction.ts +2 -2
  19. package/src/api/com/atproto/admin/util.ts +3 -1
  20. package/src/api/com/atproto/temp/fetchLabels.ts +30 -0
  21. package/src/api/index.ts +4 -0
  22. package/src/config.ts +6 -6
  23. package/src/context.ts +11 -9
  24. package/src/db/periodic-moderation-action-reversal.ts +1 -9
  25. package/src/lexicon/index.ts +22 -0
  26. package/src/lexicon/lexicons.ts +192 -129
  27. package/src/lexicon/types/app/bsky/actor/defs.ts +2 -2
  28. package/src/lexicon/types/app/bsky/actor/searchActors.ts +2 -2
  29. package/src/lexicon/types/app/bsky/actor/searchActorsTypeahead.ts +2 -2
  30. package/src/lexicon/types/app/bsky/feed/searchPosts.ts +3 -3
  31. package/src/lexicon/types/app/bsky/graph/defs.ts +2 -2
  32. package/src/lexicon/types/app/bsky/unspecced/searchActorsSkeleton.ts +4 -4
  33. package/src/lexicon/types/app/bsky/unspecced/searchPostsSkeleton.ts +3 -3
  34. package/src/lexicon/types/com/atproto/admin/defs.ts +5 -3
  35. package/src/lexicon/types/com/atproto/admin/disableAccountInvites.ts +1 -1
  36. package/src/lexicon/types/com/atproto/admin/enableAccountInvites.ts +1 -1
  37. package/src/lexicon/types/com/atproto/admin/getModerationReports.ts +3 -3
  38. package/src/lexicon/types/com/atproto/admin/takeModerationAction.ts +1 -1
  39. package/src/lexicon/types/com/atproto/label/defs.ts +9 -9
  40. package/src/lexicon/types/com/atproto/label/queryLabels.ts +2 -2
  41. package/src/lexicon/types/com/atproto/repo/applyWrites.ts +1 -1
  42. package/src/lexicon/types/com/atproto/repo/createRecord.ts +2 -2
  43. package/src/lexicon/types/com/atproto/repo/deleteRecord.ts +2 -2
  44. package/src/lexicon/types/com/atproto/repo/listRecords.ts +1 -1
  45. package/src/lexicon/types/com/atproto/repo/putRecord.ts +3 -3
  46. package/src/lexicon/types/com/atproto/server/getSession.ts +1 -0
  47. package/src/lexicon/types/com/atproto/sync/listBlobs.ts +1 -1
  48. package/src/lexicon/types/com/atproto/sync/subscribeRepos.ts +4 -4
  49. package/src/lexicon/types/com/atproto/temp/fetchLabels.ts +47 -0
  50. package/tests/admin/get-repo.test.ts +33 -0
  51. package/tests/views/suggestions.test.ts +15 -7
@@ -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
  }
@@ -8,6 +8,7 @@ export interface OutputSchema {
8
8
  did: string;
9
9
  email?: string;
10
10
  emailConfirmed?: boolean;
11
+ didDoc?: {};
11
12
  [k: string]: unknown;
12
13
  }
13
14
  export declare type HandlerInput = undefined;
@@ -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.13",
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.31.2",
35
+ "sharp": "^0.32.6",
36
36
  "typed-emitter": "^2.1.0",
37
37
  "uint8arrays": "3.0.0",
38
- "@atproto/api": "^0.6.22",
38
+ "@atproto/api": "^0.6.23",
39
39
  "@atproto/common": "^0.3.3",
40
- "@atproto/crypto": "^0.2.3",
40
+ "@atproto/crypto": "^0.3.0",
41
41
  "@atproto/syntax": "^0.1.4",
42
- "@atproto/identity": "^0.3.1",
42
+ "@atproto/identity": "^0.3.2",
43
43
  "@atproto/lexicon": "^0.3.0",
44
- "@atproto/repo": "^0.3.4",
45
- "@atproto/xrpc-server": "^0.4.0"
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.22",
57
- "@atproto/dev-env": "^0.2.13",
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.1",
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 { limit, cursor, viewer } = params
45
+ const { viewer } = params
46
+ const alreadyIncluded = parseCursor(params.cursor)
46
47
  const { ref } = db.db.dynamic
47
- let suggestionsQb = db.db
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
- if (cursor) {
66
- const cursorRow = await db.db
67
- .selectFrom('suggested_follow')
68
- .where('did', '=', cursor)
69
- .selectAll()
70
- .executeTakeFirst()
71
- if (cursorRow) {
72
- suggestionsQb = suggestionsQb.where(
73
- 'suggested_follow.order',
74
- '>',
75
- cursorRow.order,
76
- )
77
- }
78
- }
79
- const suggestions = await suggestionsQb.execute()
80
- return { params, suggestions, cursor: suggestions.at(-1)?.did }
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
- const parentsByUri = parents.reduce((acc, parent) => {
259
- return Object.assign(acc, { [parent.postUri]: parent })
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(parentsByUri, post.replyParent, parentHeight)
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 { did, subjects } = restored
90
- const agent = await ctx.pdsAdminAgent(did)
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
+ }