+24
__generated__/index.ts
+24
__generated__/index.ts
···
13
13
import * as SocialGrainGalleryGetGalleryThread from './types/social/grain/gallery/getGalleryThread.ts'
14
14
import * as SocialGrainGalleryGetActorGalleries from './types/social/grain/gallery/getActorGalleries.ts'
15
15
import * as SocialGrainGalleryGetGallery from './types/social/grain/gallery/getGallery.ts'
16
+
import * as SocialGrainGraphGetFollowers from './types/social/grain/graph/getFollowers.ts'
17
+
import * as SocialGrainGraphGetFollows from './types/social/grain/graph/getFollows.ts'
16
18
import * as SocialGrainFeedGetTimeline from './types/social/grain/feed/getTimeline.ts'
17
19
import * as SocialGrainActorGetProfile from './types/social/grain/actor/getProfile.ts'
18
20
import * as SocialGrainActorSearchActors from './types/social/grain/actor/searchActors.ts'
···
272
274
273
275
constructor(server: Server) {
274
276
this._server = server
277
+
}
278
+
279
+
getFollowers<AV extends AuthVerifier>(
280
+
cfg: ConfigOf<
281
+
AV,
282
+
SocialGrainGraphGetFollowers.Handler<ExtractAuth<AV>>,
283
+
SocialGrainGraphGetFollowers.HandlerReqCtx<ExtractAuth<AV>>
284
+
>,
285
+
) {
286
+
const nsid = 'social.grain.graph.getFollowers' // @ts-ignore
287
+
return this._server.xrpc.method(nsid, cfg)
288
+
}
289
+
290
+
getFollows<AV extends AuthVerifier>(
291
+
cfg: ConfigOf<
292
+
AV,
293
+
SocialGrainGraphGetFollows.Handler<ExtractAuth<AV>>,
294
+
SocialGrainGraphGetFollows.HandlerReqCtx<ExtractAuth<AV>>
295
+
>,
296
+
) {
297
+
const nsid = 'social.grain.graph.getFollows' // @ts-ignore
298
+
return this._server.xrpc.method(nsid, cfg)
275
299
}
276
300
}
277
301
+108
__generated__/lexicons.ts
+108
__generated__/lexicons.ts
···
2948
2948
},
2949
2949
},
2950
2950
},
2951
+
SocialGrainGraphGetFollowers: {
2952
+
lexicon: 1,
2953
+
id: 'social.grain.graph.getFollowers',
2954
+
defs: {
2955
+
main: {
2956
+
type: 'query',
2957
+
description:
2958
+
'Enumerates accounts which follow a specified account (actor).',
2959
+
parameters: {
2960
+
type: 'params',
2961
+
required: ['actor'],
2962
+
properties: {
2963
+
actor: {
2964
+
type: 'string',
2965
+
format: 'at-identifier',
2966
+
},
2967
+
limit: {
2968
+
type: 'integer',
2969
+
minimum: 1,
2970
+
maximum: 100,
2971
+
default: 50,
2972
+
},
2973
+
cursor: {
2974
+
type: 'string',
2975
+
},
2976
+
},
2977
+
},
2978
+
output: {
2979
+
encoding: 'application/json',
2980
+
schema: {
2981
+
type: 'object',
2982
+
required: ['subject', 'followers'],
2983
+
properties: {
2984
+
subject: {
2985
+
type: 'ref',
2986
+
ref: 'lex:social.grain.actor.defs#profileView',
2987
+
},
2988
+
cursor: {
2989
+
type: 'string',
2990
+
},
2991
+
followers: {
2992
+
type: 'array',
2993
+
items: {
2994
+
type: 'ref',
2995
+
ref: 'lex:social.grain.actor.defs#profileView',
2996
+
},
2997
+
},
2998
+
},
2999
+
},
3000
+
},
3001
+
},
3002
+
},
3003
+
},
3004
+
SocialGrainGraphGetFollows: {
3005
+
lexicon: 1,
3006
+
id: 'social.grain.graph.getFollows',
3007
+
defs: {
3008
+
main: {
3009
+
type: 'query',
3010
+
description:
3011
+
'Enumerates accounts which a specified account (actor) follows.',
3012
+
parameters: {
3013
+
type: 'params',
3014
+
required: ['actor'],
3015
+
properties: {
3016
+
actor: {
3017
+
type: 'string',
3018
+
format: 'at-identifier',
3019
+
},
3020
+
limit: {
3021
+
type: 'integer',
3022
+
minimum: 1,
3023
+
maximum: 100,
3024
+
default: 50,
3025
+
},
3026
+
cursor: {
3027
+
type: 'string',
3028
+
},
3029
+
},
3030
+
},
3031
+
output: {
3032
+
encoding: 'application/json',
3033
+
schema: {
3034
+
type: 'object',
3035
+
required: ['subject', 'follows'],
3036
+
properties: {
3037
+
subject: {
3038
+
type: 'ref',
3039
+
ref: 'lex:social.grain.actor.defs#profileView',
3040
+
},
3041
+
cursor: {
3042
+
type: 'string',
3043
+
},
3044
+
follows: {
3045
+
type: 'array',
3046
+
items: {
3047
+
type: 'ref',
3048
+
ref: 'lex:social.grain.actor.defs#profileView',
3049
+
},
3050
+
},
3051
+
},
3052
+
},
3053
+
},
3054
+
},
3055
+
},
3056
+
},
2951
3057
SocialGrainLabelerDefs: {
2952
3058
lexicon: 1,
2953
3059
id: 'social.grain.labeler.defs',
···
4021
4127
SocialGrainGalleryGetActorGalleries: 'social.grain.gallery.getActorGalleries',
4022
4128
SocialGrainGalleryGetGallery: 'social.grain.gallery.getGallery',
4023
4129
SocialGrainGraphFollow: 'social.grain.graph.follow',
4130
+
SocialGrainGraphGetFollowers: 'social.grain.graph.getFollowers',
4131
+
SocialGrainGraphGetFollows: 'social.grain.graph.getFollows',
4024
4132
SocialGrainLabelerDefs: 'social.grain.labeler.defs',
4025
4133
SocialGrainLabelerService: 'social.grain.labeler.service',
4026
4134
SocialGrainFeedGetTimeline: 'social.grain.feed.getTimeline',
+55
-8
src/api/mod.ts
+55
-8
src/api/mod.ts
···
28
28
QueryParams as GetGalleryThreadQueryParams,
29
29
} from "$lexicon/types/social/grain/gallery/getGalleryThread.ts";
30
30
import {
31
+
OutputSchema as GetFollowersOutputSchema,
32
+
QueryParams as GetFollowersQueryParams,
33
+
} from "$lexicon/types/social/grain/graph/getFollowers.ts";
34
+
import {
35
+
OutputSchema as GetFollowsOutputSchema,
36
+
QueryParams as GetFollowsQueryParams,
37
+
} from "$lexicon/types/social/grain/graph/getFollows.ts";
38
+
import {
31
39
OutputSchema as GetNotificationsOutputSchema,
32
40
} from "$lexicon/types/social/grain/notification/getNotifications.ts";
41
+
33
42
import { AtUri } from "@atproto/syntax";
34
43
import { BffMiddleware, route } from "@bigmoves/bff";
35
44
import {
36
45
getActorGalleries,
37
46
getActorGalleryFavs,
47
+
getActorProfile,
38
48
getActorProfileDetailed,
39
49
searchActors,
40
50
} from "../lib/actor.ts";
41
51
import { BadRequestError } from "../lib/errors.ts";
52
+
import {
53
+
getFollowersWithProfiles,
54
+
getFollowingWithProfiles,
55
+
} from "../lib/follow.ts";
42
56
import { getGalleriesByHashtag, getGallery } from "../lib/gallery.ts";
43
57
import { getNotifications } from "../lib/notifications.ts";
44
58
import { getTimeline } from "../lib/timeline.ts";
···
154
168
);
155
169
},
156
170
),
171
+
route("/xrpc/social.grain.graph.getFollows", (req, _params, ctx) => {
172
+
const url = new URL(req.url);
173
+
const { actor } = getFollowsQueryParams(url);
174
+
const subject = getActorProfile(actor, ctx);
175
+
const follows = getFollowingWithProfiles(actor, ctx);
176
+
return ctx.json({
177
+
subject,
178
+
follows,
179
+
} as GetFollowsOutputSchema);
180
+
}),
181
+
route("/xrpc/social.grain.graph.getFollowers", (req, _params, ctx) => {
182
+
const url = new URL(req.url);
183
+
const { actor } = getFollowersQueryParams(url);
184
+
const subject = getActorProfile(actor, ctx);
185
+
const followers = getFollowersWithProfiles(actor, ctx);
186
+
return ctx.json({
187
+
subject,
188
+
followers,
189
+
} as GetFollowersOutputSchema);
190
+
}),
157
191
];
158
192
159
193
function getProfileQueryParams(url: URL): GetProfileQueryParams {
···
207
241
return { q, limit, cursor };
208
242
}
209
243
210
-
// function getNotificationsQueryParams(url: URL): GetNotificationsQueryParams {
211
-
// const limit = parseInt(url.searchParams.get("limit") ?? "50", 10);
212
-
// if (isNaN(limit) || limit <= 0) {
213
-
// throw new BadRequestError("Invalid limit parameter");
214
-
// }
215
-
// const cursor = url.searchParams.get("cursor") ?? undefined;
216
-
// return { limit, cursor };
217
-
// }
244
+
function getFollowsQueryParams(url: URL): GetFollowsQueryParams {
245
+
const actor = url.searchParams.get("actor");
246
+
if (!actor) throw new BadRequestError("Missing actor parameter");
247
+
const limit = parseInt(url.searchParams.get("limit") ?? "50", 10);
248
+
if (isNaN(limit) || limit <= 0) {
249
+
throw new BadRequestError("Invalid limit parameter");
250
+
}
251
+
const cursor = url.searchParams.get("cursor") ?? undefined;
252
+
return { actor, limit, cursor };
253
+
}
254
+
255
+
function getFollowersQueryParams(url: URL): GetFollowersQueryParams {
256
+
const actor = url.searchParams.get("actor");
257
+
if (!actor) throw new BadRequestError("Missing actor parameter");
258
+
const limit = parseInt(url.searchParams.get("limit") ?? "50", 10);
259
+
if (isNaN(limit) || limit <= 0) {
260
+
throw new BadRequestError("Invalid limit parameter");
261
+
}
262
+
const cursor = url.searchParams.get("cursor") ?? undefined;
263
+
return { actor, limit, cursor };
264
+
}
218
265
219
266
function getTimelineQueryParams(url: URL): GetTimelineQueryParams {
220
267
const algorithm = url.searchParams.get("algorithm") ?? undefined;