-
-
Notifications
You must be signed in to change notification settings - Fork 424
Expand file tree
/
Copy pathauthor-profiles.get.ts
More file actions
86 lines (75 loc) · 2.39 KB
/
author-profiles.get.ts
File metadata and controls
86 lines (75 loc) · 2.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import * as v from 'valibot'
import { CACHE_MAX_AGE_ONE_DAY, BLUESKY_API } from '#shared/utils/constants'
import { AuthorSchema } from '#shared/schemas/blog'
import type { Author, ResolvedAuthor } from '#shared/schemas/blog'
type ProfilesResponse = {
profiles: Array<{
did: string
handle: string
displayName?: string
avatar?: string
}>
}
export default defineCachedEventHandler(
async event => {
const query = getQuery(event)
const authorsParam = query.authors
if (!authorsParam || typeof authorsParam !== 'string') {
throw createError({
statusCode: 400,
statusMessage: 'authors query parameter is required (JSON array)',
})
}
let authors: Author[]
try {
const parsed = JSON.parse(authorsParam)
authors = v.parse(v.array(AuthorSchema), parsed)
} catch (error) {
if (error instanceof v.ValiError) {
throw createError({
statusCode: 400,
statusMessage: `Invalid authors format: ${error.message}`,
})
}
throw createError({
statusCode: 400,
statusMessage: 'authors must be valid JSON',
})
}
if (!Array.isArray(authors) || authors.length === 0) {
return { authors: [] }
}
const handles = authors.filter(a => a.blueskyHandle).map(a => a.blueskyHandle as string)
if (handles.length === 0) {
return {
authors: authors.map(author => Object.assign(author, { avatar: null, profileUrl: null })),
}
}
const response = await $fetch<ProfilesResponse>(`${BLUESKY_API}app.bsky.actor.getProfiles`, {
query: { actors: handles },
}).catch(() => ({ profiles: [] }))
const avatarMap = new Map<string, string>()
for (const profile of response.profiles) {
if (profile.avatar) {
avatarMap.set(profile.handle, profile.avatar)
}
}
const resolvedAuthors: ResolvedAuthor[] = authors.map(author =>
Object.assign(author, {
avatar: author.blueskyHandle ? avatarMap.get(author.blueskyHandle) || null : null,
profileUrl: author.blueskyHandle
? `https://bsky.app/profile/${author.blueskyHandle}`
: null,
}),
)
return { authors: resolvedAuthors }
},
{
name: 'author-profiles',
maxAge: CACHE_MAX_AGE_ONE_DAY,
getKey: event => {
const { authors } = getQuery(event)
return `author-profiles:${authors ?? 'npmx.dev'}`
},
},
)