-
-
Notifications
You must be signed in to change notification settings - Fork 419
feat: add github stars, issues and created at to comparison page #2479
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
144e806
e4886a5
8d2cff7
3a99631
9c6f4d8
b517792
0127286
8434189
3865fc1
2693e16
3e4fccd
9df70fe
f64fd04
85c59be
9cb87b1
e29ae1f
2adcf4a
96fdccf
5b37d61
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,3 @@ | ||||||||||||||||
| import { setTimeout } from 'node:timers/promises' | ||||||||||||||||
| import { CACHE_MAX_AGE_ONE_DAY } from '#shared/utils/constants' | ||||||||||||||||
|
|
||||||||||||||||
| type GitHubContributorWeek = { | ||||||||||||||||
|
|
@@ -26,38 +25,13 @@ export default defineCachedEventHandler( | |||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| const url = `https://api.github.com/repos/${owner}/${repo}/stats/contributors` | ||||||||||||||||
| const headers = { | ||||||||||||||||
| 'User-Agent': 'npmx', | ||||||||||||||||
| 'Accept': 'application/vnd.github+json', | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| const maxAttempts = 6 | ||||||||||||||||
| let delayMs = 1000 | ||||||||||||||||
|
|
||||||||||||||||
| try { | ||||||||||||||||
| for (let attempt = 0; attempt < maxAttempts; attempt += 1) { | ||||||||||||||||
| const response = await $fetch.raw<GitHubContributorStats[]>(url, { headers }) | ||||||||||||||||
| const status = response.status | ||||||||||||||||
|
|
||||||||||||||||
| if (status === 200) { | ||||||||||||||||
| return Array.isArray(response._data) ? response._data : [] | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| if (status === 204) { | ||||||||||||||||
| return [] | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| if (status === 202) { | ||||||||||||||||
| if (attempt === maxAttempts - 1) return [] | ||||||||||||||||
| await setTimeout(delayMs) | ||||||||||||||||
| delayMs = Math.min(delayMs * 2, 16_000) | ||||||||||||||||
| continue | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| return [] | ||||||||||||||||
| } | ||||||||||||||||
| const data = await fetchGitHubWithRetries<GitHubContributorStats[]>(url, { | ||||||||||||||||
| maxAttempts: 6, | ||||||||||||||||
| }) | ||||||||||||||||
|
Comment on lines
+30
to
+32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's find the file under review
fd "contributors-evolution" -t fRepository: npmx-dev/npmx.dev Length of output: 43 🏁 Script executed: # Search for the fetchGitHubWithRetries function definition
rg "fetchGitHubWithRetries" -t ts -t tsx --max-count=20 -A 5 -B 2Repository: npmx-dev/npmx.dev Length of output: 88 🏁 Script executed: # Look for function implementation and type definitions
rg "function fetchGitHubWithRetries|const fetchGitHubWithRetries" -t ts -t tsx -A 15Repository: npmx-dev/npmx.dev Length of output: 88 🏁 Script executed: # Find the specific file being reviewed
find . -name "*.get.ts" -path "*contributors-evolution*"Repository: npmx-dev/npmx.dev Length of output: 125 🏁 Script executed: # Search for fetchGitHubWithRetries without file type flags
rg "fetchGitHubWithRetries" -A 10 -B 2Repository: npmx-dev/npmx.dev Length of output: 2684 🏁 Script executed: # Also search for timeout-related configuration in GitHub API utilities
rg "timeout" --max-count=30Repository: npmx-dev/npmx.dev Length of output: 6996 🏁 Script executed: # Read the full implementation of fetchGitHubWithRetries
head -100 server/utils/github.tsRepository: npmx-dev/npmx.dev Length of output: 1485 🏁 Script executed: # Look for GitHubFetchOptions type definition
rg "GitHubFetchOptions" -A 8 -B 2Repository: npmx-dev/npmx.dev Length of output: 941 Add an explicit timeout for the GitHub call. The Suggested fix const data = await fetchGitHubWithRetries<GitHubContributorStats[]>(url, {
maxAttempts: 6,
+ timeout: 10_000,
})📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||
|
|
||||||||||||||||
| return [] | ||||||||||||||||
| return Array.isArray(data) ? data : [] | ||||||||||||||||
| } catch { | ||||||||||||||||
| return [] | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import { CACHE_MAX_AGE_ONE_HOUR } from '#shared/utils/constants' | ||
|
|
||
| interface GitHubSearchResponse { | ||
| total_count: number | ||
| } | ||
|
|
||
| export interface GithubIssueCountResponse { | ||
| owner: string | ||
| repo: string | ||
| issues: number | null | ||
| } | ||
|
|
||
| export default defineCachedEventHandler( | ||
| async (event): Promise<GithubIssueCountResponse> => { | ||
| const owner = getRouterParam(event, 'owner') | ||
| const repo = getRouterParam(event, 'repo') | ||
|
|
||
| if (!owner || !repo) { | ||
| throw createError({ | ||
| statusCode: 400, | ||
| statusMessage: 'Owner and repo are required parameters.', | ||
| }) | ||
| } | ||
|
|
||
| const query = `repo:${owner}/${repo} is:issue is:open` | ||
| const url = `https://api.github.com/search/issues?q=${encodeURIComponent(query)}&per_page=1` | ||
|
|
||
| try { | ||
| const data = await fetchGitHubWithRetries<GitHubSearchResponse>(url, { | ||
| timeout: 10000, | ||
| }) | ||
|
|
||
| return { | ||
| owner, | ||
| repo, | ||
| issues: typeof data?.total_count === 'number' ? data.total_count : null, | ||
| } | ||
| } catch { | ||
| throw createError({ | ||
| statusCode: 500, | ||
| statusMessage: 'Failed to fetch issue count from GitHub', | ||
| }) | ||
| } | ||
| }, | ||
| { | ||
| maxAge: CACHE_MAX_AGE_ONE_HOUR, | ||
| swr: true, | ||
| name: 'github-issue-count', | ||
| getKey: event => { | ||
| const owner = getRouterParam(event, 'owner') | ||
| const repo = getRouterParam(event, 'repo') | ||
| return `${owner}/${repo}` | ||
| }, | ||
| }, | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| import { setTimeout } from 'node:timers/promises' | ||
|
|
||
| export interface GitHubFetchOptions extends NonNullable<Parameters<typeof $fetch.raw>[1]> { | ||
| maxAttempts?: number | ||
| } | ||
|
|
||
| export async function fetchGitHubWithRetries<T>( | ||
| url: string, | ||
| options: GitHubFetchOptions = {}, | ||
| ): Promise<T | null> { | ||
| const { maxAttempts = 3, ...fetchOptions } = options | ||
| let delayMs = 1000 | ||
|
alexdln marked this conversation as resolved.
|
||
|
|
||
| const defaultHeaders = { | ||
| 'Accept': 'application/vnd.github+json', | ||
| 'User-Agent': 'npmx', | ||
| 'X-GitHub-Api-Version': '2026-03-10', | ||
| } | ||
|
|
||
| for (let attempt = 0; attempt < maxAttempts; attempt += 1) { | ||
| try { | ||
| const headers = new Headers(defaultHeaders) | ||
| for (const [key, value] of new Headers(fetchOptions.headers)) { | ||
| headers.set(key, value) | ||
| } | ||
| const response = await $fetch.raw(url, { | ||
| ...fetchOptions, | ||
| headers, | ||
| }) | ||
|
|
||
| if (response.status === 200) { | ||
| return (response._data as T) ?? null | ||
| } | ||
|
|
||
| if (response.status === 204) { | ||
| return null | ||
| } | ||
|
|
||
| if (response.status === 202) { | ||
| if (attempt === maxAttempts - 1) break | ||
| await setTimeout(delayMs) | ||
| delayMs = Math.min(delayMs * 2, 16_000) | ||
| continue | ||
| } | ||
|
|
||
| break | ||
| } catch (error: unknown) { | ||
| if (attempt === maxAttempts - 1) { | ||
| throw error | ||
| } | ||
| await setTimeout(delayMs) | ||
| delayMs = Math.min(delayMs * 2, 16_000) | ||
| } | ||
| } | ||
|
|
||
| throw new Error(`Failed to fetch from GitHub after ${maxAttempts} attempts`) | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.