@@ -3,7 +3,7 @@ import { fetchGitHubUserData } from "../../../lib/github";
33import { calculateUserScore } from "../../../lib/score" ;
44import { normalizeSelectedLanguages } from "@/lib/scoring/languageScoring" ;
55import { toSafeApiError } from "@/lib/github-graphql-client" ;
6- import type { CompareInsights } from "@/types/api-response" ;
6+ import type { CompareInsights , SafeApiError } from "@/types/api-response" ;
77import {
88 DEFAULT_LOCALE ,
99 LOCALE_COOKIE ,
@@ -14,6 +14,18 @@ import {
1414
1515export const runtime = "nodejs" ;
1616
17+ class CompareUserFetchError extends Error {
18+ readonly username : string ;
19+ readonly causeError : unknown ;
20+
21+ constructor ( username : string , causeError : unknown ) {
22+ super ( `Failed to fetch GitHub data for ${ username } ` ) ;
23+ this . name = "CompareUserFetchError" ;
24+ this . username = username ;
25+ this . causeError = causeError ;
26+ }
27+ }
28+
1729type ComparedUserResult = {
1830 username : string ;
1931 name : string | null ;
@@ -36,6 +48,8 @@ type ComparedUserResult = {
3648 explanations : ReturnType < typeof calculateUserScore > [ "explanations" ] ;
3749} ;
3850
51+ type ClientSafeError = Pick < SafeApiError , "code" | "message" | "targetUsernames" > ;
52+
3953function parseSelectedLanguagesFromSearchParams (
4054 searchParams : URLSearchParams ,
4155) : string [ ] {
@@ -292,7 +306,13 @@ async function compareUsers(
292306 const results : ComparedUserResult [ ] = [ ] ;
293307
294308 for ( const username of usernames ) {
295- const data = await fetchGitHubUserData ( username ) ;
309+ let data : Awaited < ReturnType < typeof fetchGitHubUserData > > ;
310+ try {
311+ data = await fetchGitHubUserData ( username ) ;
312+ } catch ( error : unknown ) {
313+ throw new CompareUserFetchError ( username , error ) ;
314+ }
315+
296316 const score = calculateUserScore (
297317 {
298318 ...data ,
@@ -341,6 +361,14 @@ function toApiErrorStatus(code: ReturnType<typeof toSafeApiError>["code"]): numb
341361 }
342362}
343363
364+ function toClientSafeError ( error : SafeApiError ) : ClientSafeError {
365+ return {
366+ code : error . code ,
367+ message : error . message ,
368+ targetUsernames : error . targetUsernames ,
369+ } ;
370+ }
371+
344372export async function GET ( request : Request ) {
345373 const { searchParams } = new URL ( request . url ) ;
346374 const usernames = searchParams
@@ -364,16 +392,39 @@ export async function GET(request: Request) {
364392 return NextResponse . json ( { success : true , users, ...winnerData , insights } ) ;
365393 } catch ( error : unknown ) {
366394 console . error ( "GitHub score error:" , error ) ;
367- const safeError =
368- error instanceof Error && error . message === "User not found"
369- ? { code : "GITHUB_NOT_FOUND" as const , message : "GitHub user not found" }
370- : toSafeApiError ( error ) ;
395+
396+ let safeError : SafeApiError ;
397+
398+ if ( error instanceof CompareUserFetchError ) {
399+ const mappedCause = toSafeApiError ( error . causeError ) ;
400+ if (
401+ mappedCause . code === "GITHUB_NOT_FOUND" ||
402+ ( error . causeError instanceof Error &&
403+ error . causeError . message === "User not found" )
404+ ) {
405+ safeError = {
406+ code : "GITHUB_NOT_FOUND" ,
407+ message : "GitHub user not found" ,
408+ targetUsernames : [ error . username ] ,
409+ rateLimit : mappedCause . rateLimit ,
410+ } ;
411+ } else {
412+ safeError = mappedCause ;
413+ }
414+ } else {
415+ safeError =
416+ error instanceof Error && error . message === "User not found"
417+ ? { code : "GITHUB_NOT_FOUND" , message : "GitHub user not found" }
418+ : toSafeApiError ( error ) ;
419+ }
420+
421+ const clientSafeError = toClientSafeError ( safeError ) ;
371422
372423 return NextResponse . json (
373424 {
374425 success : false ,
375- error : safeError . message ,
376- errorDetails : safeError ,
426+ error : clientSafeError . message ,
427+ errorDetails : clientSafeError ,
377428 } ,
378429 { status : toApiErrorStatus ( safeError . code ) } ,
379430 ) ;
0 commit comments