mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-28 09:23:08 +08:00
fix(types): add runtime validation for GitHub API response in skill-hub-routes
- Replace GitHubTreeEntry with GitHubContentEntry matching actual API response
- Add runtime array validation to prevent unexpected response formats
- Normalize GitHub API types ('file'/'dir') to internal types ('blob'/'tree')
- Validate required fields (name, path, type) for each entry
This fixes potential runtime errors when GitHub API response structure
differs from expected type definition.
This commit is contained in:
@@ -462,20 +462,37 @@ function buildDownloadUrlFromPath(skillPath: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch skill directory contents from GitHub API
|
* GitHub Contents API response entry
|
||||||
* Returns list of files in the directory
|
* @see https://docs.github.com/en/rest/repos/contents#get-repository-content
|
||||||
*/
|
*/
|
||||||
interface GitHubTreeEntry {
|
interface GitHubContentEntry {
|
||||||
|
name: string;
|
||||||
|
path: string;
|
||||||
|
sha: string;
|
||||||
|
size?: number;
|
||||||
|
type: 'file' | 'dir' | 'submodule' | 'symlink';
|
||||||
|
download_url?: string;
|
||||||
|
url: string;
|
||||||
|
html_url?: string;
|
||||||
|
git_url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal normalized entry type for processing
|
||||||
|
*/
|
||||||
|
interface NormalizedTreeEntry {
|
||||||
path: string;
|
path: string;
|
||||||
mode: string;
|
|
||||||
type: 'blob' | 'tree';
|
type: 'blob' | 'tree';
|
||||||
sha: string;
|
sha: string;
|
||||||
size?: number;
|
size?: number;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchSkillDirectoryContents(skillPath: string): Promise<GitHubTreeEntry[]> {
|
/**
|
||||||
// Use GitHub API to get tree contents
|
* Fetch skill directory contents from GitHub Contents API
|
||||||
|
* Returns normalized list of files and directories
|
||||||
|
*/
|
||||||
|
async function fetchSkillDirectoryContents(skillPath: string): Promise<NormalizedTreeEntry[]> {
|
||||||
const apiUrl = `https://api.github.com/repos/${GITHUB_CONFIG.owner}/${GITHUB_CONFIG.repo}/contents/${skillPath}?ref=${GITHUB_CONFIG.branch}`;
|
const apiUrl = `https://api.github.com/repos/${GITHUB_CONFIG.owner}/${GITHUB_CONFIG.repo}/contents/${skillPath}?ref=${GITHUB_CONFIG.branch}`;
|
||||||
|
|
||||||
const response = await fetch(apiUrl, {
|
const response = await fetch(apiUrl, {
|
||||||
@@ -489,7 +506,30 @@ async function fetchSkillDirectoryContents(skillPath: string): Promise<GitHubTre
|
|||||||
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
|
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.json() as Promise<GitHubTreeEntry[]>;
|
const contents = await response.json();
|
||||||
|
|
||||||
|
// Runtime validation: must be an array
|
||||||
|
if (!Array.isArray(contents)) {
|
||||||
|
throw new Error(`Unexpected GitHub API response for directory: ${skillPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize and validate each entry
|
||||||
|
return contents.map((entry: GitHubContentEntry) => {
|
||||||
|
if (!entry.name || !entry.path || !entry.type) {
|
||||||
|
throw new Error(`Invalid GitHub API entry: ${JSON.stringify(entry)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize GitHub type to internal type
|
||||||
|
const normalizedType: 'blob' | 'tree' = entry.type === 'dir' ? 'tree' : 'blob';
|
||||||
|
|
||||||
|
return {
|
||||||
|
path: entry.path,
|
||||||
|
type: normalizedType,
|
||||||
|
sha: entry.sha,
|
||||||
|
size: entry.size,
|
||||||
|
url: entry.url,
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user