diff --git a/src/lib/components/content/FileExplorer.svelte b/src/lib/components/content/FileExplorer.svelte index e220c2a..6e0e475 100644 --- a/src/lib/components/content/FileExplorer.svelte +++ b/src/lib/components/content/FileExplorer.svelte @@ -117,9 +117,13 @@ } // Use GitHub API helper for GitHub repos (handles rate limiting and token fallback) - const response = url.includes('github.com') - ? await fetchGitHubApi(apiUrl) - : await fetch(apiUrl); + let response: Response; + if (url.includes('github.com')) { + const apiResult = await fetchGitHubApi(apiUrl); + response = apiResult.response; + } else { + response = await fetch(apiUrl); + } if (!response.ok) { throw new Error(`Failed to fetch file: ${response.status} ${response.statusText}`); diff --git a/src/lib/services/content/git-repo-fetcher.ts b/src/lib/services/content/git-repo-fetcher.ts index 9081ea0..8e78e84 100644 --- a/src/lib/services/content/git-repo-fetcher.ts +++ b/src/lib/services/content/git-repo-fetcher.ts @@ -18,6 +18,7 @@ export interface GitRepoInfo { content: string; format: 'markdown' | 'asciidoc'; }; + usingGitHubToken?: boolean; // Indicates if GitHub API token was used } export interface GitBranch { @@ -89,19 +90,29 @@ function parseGitUrl(url: string): { platform: string; owner: string; repo: stri */ async function fetchFromGitHub(owner: string, repo: string): Promise { try { - const repoResponse = await fetchGitHubApi(`https://api.github.com/repos/${owner}/${repo}`); - if (!repoResponse.ok) { - console.warn(`GitHub API error for repo ${owner}/${repo}: ${repoResponse.status} ${repoResponse.statusText}`); + const repoApiResult = await fetchGitHubApi(`https://api.github.com/repos/${owner}/${repo}`); + if (!repoApiResult.response.ok) { + console.warn(`GitHub API error for repo ${owner}/${repo}: ${repoApiResult.response.status} ${repoApiResult.response.statusText}`); return null; } - const repoData = await repoResponse.json(); + const repoData = await repoApiResult.response.json(); + + // Track if any request used a token + let usingToken = repoApiResult.usedToken; const defaultBranch = repoData.default_branch || 'main'; - const [branchesResponse, commitsResponse, treeResponse] = await Promise.all([ + const [branchesResult, commitsResult, treeResult] = await Promise.all([ fetchGitHubApi(`https://api.github.com/repos/${owner}/${repo}/branches`), fetchGitHubApi(`https://api.github.com/repos/${owner}/${repo}/commits?per_page=10`), - fetchGitHubApi(`https://api.github.com/repos/${owner}/${repo}/git/trees/${defaultBranch}?recursive=1`).catch(() => null) + fetchGitHubApi(`https://api.github.com/repos/${owner}/${repo}/git/trees/${defaultBranch}?recursive=1`).catch(() => ({ response: null as any, usedToken: false })) ]); + + // Update token usage flag if any request used a token + usingToken = usingToken || branchesResult.usedToken || commitsResult.usedToken || (treeResult?.usedToken ?? false); + + const branchesResponse = branchesResult.response; + const commitsResponse = commitsResult.response; + const treeResponse = treeResult?.response; // Check if responses are OK and parse JSON let branchesData: any[] = []; @@ -206,10 +217,12 @@ async function fetchFromGitHub(owner: string, repo: string): Promise { - if (!r.ok) throw new Error('Not found'); - return r.json(); - }); + const readmeResult = await fetchGitHubApi(`https://api.github.com/repos/${owner}/${repo}/contents/${readmeFile}?ref=${defaultBranch}`); + if (readmeResult.usedToken) { + usingToken = true; + } + if (!readmeResult.response.ok) throw new Error('Not found'); + const readmeData = await readmeResult.response.json(); if (readmeData.content) { const content = atob(readmeData.content.replace(/\s/g, '')); readme = { @@ -244,10 +257,12 @@ async function fetchFromGitHub(owner: string, repo: string): Promise { - if (!r.ok) throw new Error('Not found'); - return r.json(); - }); + const readmeResult = await fetchGitHubApi(`https://api.github.com/repos/${owner}/${repo}/contents/${readmePath}?ref=${defaultBranch}`); + if (readmeResult.usedToken) { + usingToken = true; + } + if (!readmeResult.response.ok) throw new Error('Not found'); + const readmeData = await readmeResult.response.json(); if (readmeData.content) { const content = atob(readmeData.content.replace(/\s/g, '')); const format = readmePath.toLowerCase().endsWith('.adoc') ? 'asciidoc' : 'markdown'; @@ -271,7 +286,8 @@ async function fetchFromGitHub(owner: string, repo: string): Promise { } } +/** + * Result of a GitHub API request, including whether a token was used + */ +export interface GitHubApiResponse { + response: Response; + usedToken: boolean; +} + /** * Make a GitHub API request with automatic token fallback on rate limiting * @param url - GitHub API URL * @param options - Fetch options (headers will be merged) - * @returns Response object + * @returns Response object and whether a token was used */ export async function fetchGitHubApi( url: string, options: RequestInit = {} -): Promise { +): Promise { // First attempt without token let response = await fetch(url, { ...options, @@ -92,6 +100,8 @@ export async function fetchGitHubApi( } }); + let usedToken = false; + // Check if rate limited if (isRateLimited(response)) { console.log('GitHub API rate limit detected, attempting to use saved token...'); @@ -101,6 +111,7 @@ export async function fetchGitHubApi( if (token) { console.log('Using saved GitHub token for authenticated request'); + usedToken = true; // Retry with token (use Bearer for compatibility with both classic and fine-grained tokens) response = await fetch(url, { @@ -133,5 +144,5 @@ export async function fetchGitHubApi( } } - return response; + return { response, usedToken }; } diff --git a/src/routes/repos/[naddr]/+page.svelte b/src/routes/repos/[naddr]/+page.svelte index 5852bd7..b03a378 100644 --- a/src/routes/repos/[naddr]/+page.svelte +++ b/src/routes/repos/[naddr]/+page.svelte @@ -20,6 +20,7 @@ import { cacheEvent, getEventsByKind } from '../../../lib/services/cache/event-cache.js'; import EventMenu from '../../../lib/components/EventMenu.svelte'; import { fetchProfiles } from '../../../lib/services/user-data.js'; + import Icon from '../../../lib/components/ui/Icon.svelte'; let naddr = $derived($page.params.naddr); let repoEvent = $state(null); @@ -895,6 +896,12 @@ {/if} + {#if gitRepo?.usingGitHubToken} +
+ + Using your saved GitHub API token for authenticated requests +
+ {/if} {#if getRepoDescription()}

{getRepoDescription()}