/**
* HTTP client for GitHub API
*/
import { getGitHubMapping } from "./repo-mapping.js";
export class GitHubClient {
/**
* Fetch raw file content from GitHub
*/
async getFileContent(
searchfoxRepo: string,
filePath: string
): Promise<string> {
const mapping = getGitHubMapping(searchfoxRepo);
const url = `https://raw.githubusercontent.com/${mapping.github_repo}/${mapping.branch}/${filePath}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.text();
}
/**
* Fetch file content with line range
*/
async getFileContentWithRange(
searchfoxRepo: string,
filePath: string,
startLine?: number,
endLine?: number,
contextLines?: number
): Promise<string> {
const content = await this.getFileContent(searchfoxRepo, filePath);
const lines = content.split("\n");
// If no range specified, return full content
if (startLine === undefined && endLine === undefined) {
return content;
}
// Calculate actual range with context
const start = Math.max(0, (startLine ?? 1) - 1 - (contextLines ?? 0));
const end = Math.min(
lines.length,
(endLine ?? lines.length) + (contextLines ?? 0)
);
return lines.slice(start, end).join("\n");
}
/**
* Fetch git blame information
*/
async getBlame(
searchfoxRepo: string,
filePath: string,
_startLine?: number,
_endLine?: number
): Promise<string> {
const mapping = getGitHubMapping(searchfoxRepo);
// GitHub blame API: https://api.github.com/repos/{owner}/{repo}/commits?path={path}
const url = `https://api.github.com/repos/${mapping.github_repo}/commits?path=${filePath}&sha=${mapping.branch}`;
const response = await fetch(url, {
headers: {
Accept: "application/vnd.github.v3+json",
},
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.text();
}
}
// Singleton instance
export const githubClient = new GitHubClient();