Skip to content

Commit b4b05d2

Browse files
committed
fix: simplify some things
1 parent 2163460 commit b4b05d2

File tree

4 files changed

+56
-101
lines changed

4 files changed

+56
-101
lines changed

app/components/Package/Likes.vue

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -111,23 +111,16 @@ const likeAction = async () => {
111111
112112
try {
113113
const result = await togglePackageLike(props.packageName, currentlyLiked, user.value?.handle)
114-
115-
isLikeActionPending.value = false
116-
117-
if (result.success) {
118-
// Update with server response
119-
likesData.value = {
120-
...previousLikesState,
121-
...result.data,
122-
topLikedRank: result.data.topLikedRank ?? previousLikesState.topLikedRank,
123-
}
124-
} else {
125-
// Revert on error
126-
likesData.value = previousLikesState
127-
}
114+
likesData.value = result.success
115+
? {
116+
...previousLikesState,
117+
...result.data,
118+
topLikedRank: result.data.topLikedRank ?? previousLikesState.topLikedRank,
119+
}
120+
: previousLikesState
128121
} catch {
129-
// Revert on error
130122
likesData.value = previousLikesState
123+
} finally {
131124
isLikeActionPending.value = false
132125
}
133126
}
@@ -203,7 +196,7 @@ const likeAction = async () => {
203196
}
204197
205198
@media (prefers-reduced-motion: reduce) {
206-
.likeFloat {
199+
.like-float {
207200
display: none;
208201
}
209202
}

server/api/leaderboard/likes.get.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,5 @@ import type { LikesLeaderboardEntry } from '#shared/types/social'
33
import { getLikesLeaderboard } from '#server/utils/likes-leaderboard'
44

55
export default eventHandler(async (event): Promise<LikesLeaderboardEntry[]> => {
6-
const leaderboard = await getLikesLeaderboard(event)
7-
return leaderboard?.entries ?? []
6+
return (await getLikesLeaderboard(event)) ?? []
87
})

server/utils/likes-leaderboard.ts

Lines changed: 32 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,11 @@ const UpstreamLikesLeaderboardEntrySchema = v.object({
1010
})
1111

1212
const UpstreamLikesLeaderboardResponseSchema = v.object({
13-
totalLikes: v.optional(v.number()),
14-
totalUniqueLikers: v.optional(v.number()),
1513
leaderBoard: v.array(UpstreamLikesLeaderboardEntrySchema),
1614
})
1715

18-
type UpstreamLikesLeaderboardResponse = v.InferOutput<typeof UpstreamLikesLeaderboardResponseSchema>
19-
20-
export type ResolvedLikesLeaderboard = {
21-
totalLikes: number | null
22-
totalUniqueLikers: number | null
23-
entries: LikesLeaderboardEntry[]
24-
}
25-
2616
const LIKES_LEADERBOARD_FETCH_TIMEOUT_MS = 750
2717

28-
type LikesLeaderboardOptions = {
29-
timeoutMs?: number
30-
}
31-
3218
export const LIKES_LEADERBOARD_MAX_ENTRIES = 10
3319

3420
export function extractPackageNameFromSubjectRef(subjectRef: string): string | null {
@@ -42,82 +28,69 @@ export function extractPackageNameFromSubjectRef(subjectRef: string): string | n
4228
}
4329
}
4430

45-
export function normalizeLikesLeaderboardPayload(
46-
payload: unknown,
47-
): ResolvedLikesLeaderboard | null {
31+
export function normalizeLikesLeaderboardPayload(payload: unknown): LikesLeaderboardEntry[] | null {
4832
const parsedPayload = v.safeParse(UpstreamLikesLeaderboardResponseSchema, payload)
4933
if (!parsedPayload.success) {
5034
return null
5135
}
5236

5337
// PRECONDITION: the response is already sorted by totalLikes in descending order
54-
const entries = parsedPayload.output.leaderBoard
55-
.map((entry): LikesLeaderboardEntry | null => {
56-
const packageName = extractPackageNameFromSubjectRef(entry.subjectRef)
57-
if (!packageName) return null
58-
59-
return {
60-
rank: 0,
61-
packageName,
62-
subjectRef: entry.subjectRef,
63-
totalLikes: entry.totalLikes,
64-
}
65-
})
66-
.filter((entry): entry is LikesLeaderboardEntry => entry !== null)
67-
// oxlint-disable-next-line no-map-spread -- only a few elements
68-
.map((entry, index) => ({
69-
...entry,
70-
rank: index + 1,
71-
}))
72-
73-
return {
74-
totalLikes: parsedPayload.output.totalLikes ?? null,
75-
totalUniqueLikers: parsedPayload.output.totalUniqueLikers ?? null,
76-
entries,
77-
}
38+
return (
39+
parsedPayload.output.leaderBoard
40+
.map((entry): LikesLeaderboardEntry | null => {
41+
const packageName = extractPackageNameFromSubjectRef(entry.subjectRef)
42+
if (!packageName) return null
43+
44+
return {
45+
rank: 0,
46+
packageName,
47+
subjectRef: entry.subjectRef,
48+
totalLikes: entry.totalLikes,
49+
}
50+
})
51+
.filter((entry): entry is LikesLeaderboardEntry => entry !== null)
52+
// oxlint-disable-next-line no-map-spread -- only a few elements
53+
.map((entry, index) => ({
54+
...entry,
55+
rank: index + 1,
56+
}))
57+
)
7858
}
7959

80-
export async function getLikesLeaderboard(
81-
event: H3Event,
82-
options: LikesLeaderboardOptions = {},
83-
): Promise<ResolvedLikesLeaderboard | null> {
84-
const timeoutMs = options.timeoutMs ?? LIKES_LEADERBOARD_FETCH_TIMEOUT_MS
60+
export async function getLikesLeaderboard(event: H3Event): Promise<LikesLeaderboardEntry[] | null> {
8561
const cachedFetch = event.context.cachedFetch as CachedFetchFunction | undefined
8662
if (!cachedFetch) {
87-
console.error('Something went wrong: event.context.cachedFetch is missing. Aborting fetch.', {
88-
eventContext: event.context,
89-
})
63+
console.error('[likes-leaderboard] Missing cachedFetch in request context')
9064
return null
9165
}
9266

9367
try {
9468
const url = new URL(LIKES_LEADERBOARD_API_URL)
9569
url.searchParams.set('limit', LIKES_LEADERBOARD_MAX_ENTRIES.toString())
9670

97-
const { data } = await cachedFetch<UpstreamLikesLeaderboardResponse>(
71+
const { data } = await cachedFetch(
9872
url.toString(),
9973
{
10074
headers: {
10175
'User-Agent': 'npmx',
10276
'Accept': 'application/json',
10377
},
104-
signal: AbortSignal.timeout(timeoutMs),
78+
signal: AbortSignal.timeout(LIKES_LEADERBOARD_FETCH_TIMEOUT_MS),
10579
},
10680
CACHE_MAX_AGE_ONE_HOUR,
10781
)
10882

10983
return normalizeLikesLeaderboardPayload(data)
11084
} catch (err) {
111-
console.error('Failed to fetch likes leaderboard', { err })
85+
console.error(
86+
'[likes-leaderboard] Failed to fetch likes leaderboard:',
87+
err instanceof Error ? err.message : 'Unknown error',
88+
)
11289
return null
11390
}
11491
}
11592

116-
export async function getTopLikedRank(
117-
event: H3Event,
118-
subjectRef: string,
119-
options: LikesLeaderboardOptions = {},
120-
): Promise<number | null> {
121-
const leaderboard = await getLikesLeaderboard(event, options)
122-
return leaderboard?.entries.find(entry => entry.subjectRef === subjectRef)?.rank ?? null
93+
export async function getTopLikedRank(event: H3Event, subjectRef: string): Promise<number | null> {
94+
const leaderboard = await getLikesLeaderboard(event)
95+
return leaderboard?.find(entry => entry.subjectRef === subjectRef)?.rank ?? null
12396
}

test/unit/server/utils/likes-leaderboard.spec.ts

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -32,32 +32,26 @@ describe('extractPackageNameFromSubjectRef', () => {
3232
describe('normalizeLikesLeaderboardPayload', () => {
3333
it('normalizes upstream leaderboard payload into ranked entries', () => {
3434
const result = normalizeLikesLeaderboardPayload({
35-
totalLikes: 320,
36-
totalUniqueLikers: 75,
3735
leaderBoard: [
3836
{ subjectRef: 'https://npmx.dev/package/vue', totalLikes: 120 },
3937
{ subjectRef: 'https://npmx.dev/package/@nuxt/kit', totalLikes: 90 },
4038
],
4139
})
4240

43-
expect(result).toEqual({
44-
totalLikes: 320,
45-
totalUniqueLikers: 75,
46-
entries: [
47-
{
48-
rank: 1,
49-
packageName: 'vue',
50-
subjectRef: 'https://npmx.dev/package/vue',
51-
totalLikes: 120,
52-
},
53-
{
54-
rank: 2,
55-
packageName: '@nuxt/kit',
56-
subjectRef: 'https://npmx.dev/package/@nuxt/kit',
57-
totalLikes: 90,
58-
},
59-
],
60-
})
41+
expect(result).toEqual([
42+
{
43+
rank: 1,
44+
packageName: 'vue',
45+
subjectRef: 'https://npmx.dev/package/vue',
46+
totalLikes: 120,
47+
},
48+
{
49+
rank: 2,
50+
packageName: '@nuxt/kit',
51+
subjectRef: 'https://npmx.dev/package/@nuxt/kit',
52+
totalLikes: 90,
53+
},
54+
])
6155
})
6256

6357
it('returns null for invalid upstream payloads', () => {
@@ -78,8 +72,6 @@ describe('getLikesLeaderboard', () => {
7872
it('fetches from the external leaderboard API with limit=10', async () => {
7973
const cachedFetch = vi.fn().mockResolvedValue({
8074
data: {
81-
totalLikes: 320,
82-
totalUniqueLikers: 75,
8375
leaderBoard: [{ subjectRef: 'https://npmx.dev/package/vue', totalLikes: 120 }],
8476
},
8577
isStale: false,
@@ -106,8 +98,6 @@ describe('getTopLikedRank', () => {
10698
it('returns the matching top liked rank for a subject ref', async () => {
10799
const cachedFetch = vi.fn().mockResolvedValue({
108100
data: {
109-
totalLikes: 320,
110-
totalUniqueLikers: 75,
111101
leaderBoard: [
112102
{ subjectRef: 'https://npmx.dev/package/vue', totalLikes: 120 },
113103
{ subjectRef: 'https://npmx.dev/package/nuxt', totalLikes: 90 },

0 commit comments

Comments
 (0)