VIBN Frontend for Coolify deployment
This commit is contained in:
149
app/api/github/repo-tree/route.ts
Normal file
149
app/api/github/repo-tree/route.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { getAdminAuth, getAdminDb } from '@/lib/firebase/admin';
|
||||
|
||||
/**
|
||||
* Fetch repository file tree from GitHub
|
||||
* GET /api/github/repo-tree?owner=X&repo=Y
|
||||
*/
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const authHeader = request.headers.get('Authorization');
|
||||
if (!authHeader?.startsWith('Bearer ')) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
}
|
||||
|
||||
const idToken = authHeader.split('Bearer ')[1];
|
||||
const adminAuth = getAdminAuth();
|
||||
const adminDb = getAdminDb();
|
||||
|
||||
let userId: string;
|
||||
try {
|
||||
const decodedToken = await adminAuth.verifyIdToken(idToken);
|
||||
userId = decodedToken.uid;
|
||||
} catch (error) {
|
||||
return NextResponse.json({ error: 'Invalid token' }, { status: 401 });
|
||||
}
|
||||
|
||||
const url = new URL(request.url);
|
||||
const owner = url.searchParams.get('owner');
|
||||
const repo = url.searchParams.get('repo');
|
||||
const branch = url.searchParams.get('branch') || 'main';
|
||||
|
||||
if (!owner || !repo) {
|
||||
return NextResponse.json({ error: 'Missing owner or repo' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Get GitHub connection
|
||||
const connectionDoc = await adminDb
|
||||
.collection('githubConnections')
|
||||
.doc(userId)
|
||||
.get();
|
||||
|
||||
if (!connectionDoc.exists) {
|
||||
return NextResponse.json(
|
||||
{ error: 'GitHub not connected' },
|
||||
{ status: 404 }
|
||||
);
|
||||
}
|
||||
|
||||
const connection = connectionDoc.data()!;
|
||||
const accessToken = connection.accessToken; // TODO: Decrypt
|
||||
|
||||
// Fetch repository tree from GitHub API (recursive)
|
||||
const response = await fetch(
|
||||
`https://api.github.com/repos/${owner}/${repo}/git/trees/${branch}?recursive=1`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(`GitHub API error: ${error.message || response.statusText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// Filter to only include files (not directories)
|
||||
// and exclude common non-code files
|
||||
const excludePatterns = [
|
||||
/node_modules\//,
|
||||
/\.git\//,
|
||||
/dist\//,
|
||||
/build\//,
|
||||
/\.next\//,
|
||||
/coverage\//,
|
||||
/\.cache\//,
|
||||
/\.env/,
|
||||
/package-lock\.json$/,
|
||||
/yarn\.lock$/,
|
||||
/pnpm-lock\.yaml$/,
|
||||
/\.png$/,
|
||||
/\.jpg$/,
|
||||
/\.jpeg$/,
|
||||
/\.gif$/,
|
||||
/\.svg$/,
|
||||
/\.ico$/,
|
||||
/\.woff$/,
|
||||
/\.woff2$/,
|
||||
/\.ttf$/,
|
||||
/\.eot$/,
|
||||
/\.min\.js$/,
|
||||
/\.min\.css$/,
|
||||
/\.map$/,
|
||||
];
|
||||
|
||||
// Include common code file extensions
|
||||
const includePatterns = [
|
||||
/\.(ts|tsx|js|jsx|py|java|go|rs|cpp|c|h|cs|rb|php|swift|kt)$/,
|
||||
/\.(json|yaml|yml|toml|xml)$/,
|
||||
/\.(md|txt)$/,
|
||||
/\.(sql|graphql|proto)$/,
|
||||
/\.(css|scss|sass|less)$/,
|
||||
/\.(html|htm)$/,
|
||||
/Dockerfile$/,
|
||||
/Makefile$/,
|
||||
/README$/,
|
||||
];
|
||||
|
||||
const files = data.tree
|
||||
.filter((item: any) => item.type === 'blob')
|
||||
.filter((item: any) => {
|
||||
// Exclude patterns
|
||||
if (excludePatterns.some(pattern => pattern.test(item.path))) {
|
||||
return false;
|
||||
}
|
||||
// Include patterns
|
||||
return includePatterns.some(pattern => pattern.test(item.path));
|
||||
})
|
||||
.map((item: any) => ({
|
||||
path: item.path,
|
||||
sha: item.sha,
|
||||
size: item.size,
|
||||
url: item.url,
|
||||
}));
|
||||
|
||||
console.log(`[GitHub Tree] Found ${files.length} code files in ${owner}/${repo}`);
|
||||
|
||||
return NextResponse.json({
|
||||
owner,
|
||||
repo,
|
||||
branch,
|
||||
totalFiles: files.length,
|
||||
files,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[GitHub Tree] Error:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to fetch repository tree',
|
||||
details: error instanceof Error ? error.message : String(error),
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user