Files
learning-platform/src/lib/giteaService.js

89 lines
2.7 KiB
JavaScript

/**
* GitHub API Service
* Fetches files from a public GitHub repository directly from the browser.
* No proxy or token required for public repos.
*/
const GITHUB_API = 'https://api.github.com';
const GITHUB_RAW = 'https://raw.githubusercontent.com';
/**
* List markdown/text files in a GitHub repository folder.
* @param {string} owner - e.g. "respellion"
* @param {string} repo - e.g. "employee-handbook"
* @param {string} folder - e.g. "docs" or "" for root
* @param {string} branch - e.g. "main"
* @returns {Promise<Array<{name, sha, path}>>}
*/
export async function getRepoFolder(owner, repo, folder = '', branch = 'main') {
// Use the GitHub Git Trees API to fetch all files recursively in one request
const url = `${GITHUB_API}/repos/${owner}/${repo}/git/trees/${branch}?recursive=1`;
const res = await fetch(url, {
headers: { Accept: 'application/vnd.github+json' },
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error(`GitHub API ${res.status}: ${err.message || 'Could not list folder'}`);
}
const data = await res.json();
// If folder is 'docs', we only want paths starting with 'docs/'
const folderPrefix = folder ? folder.replace(/^\/|\/$/g, '') + '/' : '';
// Return only files (blobs) that match the folder prefix and file extensions
return data.tree
.filter(item =>
item.type === 'blob' &&
item.path.startsWith(folderPrefix) &&
(item.path.endsWith('.md') || item.path.endsWith('.txt'))
)
.map(item => ({
name: item.path.split('/').pop(),
path: item.path,
sha: item.sha
}));
}
/**
* Fetch the raw text content of a file.
* Uses raw.githubusercontent.com — no rate limits for public content.
* @param {string} owner
* @param {string} repo
* @param {string} path - e.g. "docs/ROLES.md"
* @param {string} branch
* @returns {Promise<string>}
*/
export async function getFileContent(owner, repo, path, branch = 'main') {
const url = `${GITHUB_RAW}/${owner}/${repo}/${branch}/${path}`;
const res = await fetch(url);
if (!res.ok) {
throw new Error(`Could not fetch "${path}" from GitHub (${res.status})`);
}
return res.text();
}
/**
* Parse a GitHub tree URL into its parts.
* e.g. "https://github.com/respellion/employee-handbook/tree/main/docs"
* → { owner: 'respellion', repo: 'employee-handbook', branch: 'main', folder: 'docs' }
*/
export function parseGitHubUrl(url) {
try {
const match = url.match(/github\.com\/([^/]+)\/([^/]+)(?:\/tree\/([^/]+)(?:\/(.+))?)?/);
if (!match) return null;
return {
owner: match[1],
repo: match[2],
branch: match[3] || 'main',
folder: match[4] || '',
};
} catch {
return null;
}
}