import { authApiClient } from '@/components/apis/authApiClients' export interface AttachRepositoryPayload { repository_url: string branch_name?: string user_id?: string } // -------- Repository contents -------- export interface RepoStructureEntry { name: string type: 'file' | 'directory' size?: number path: string } export interface RepoStructureResponse { repository_id: string directory_path: string structure: RepoStructureEntry[] } export async function getRepositoryStructure(repositoryId: string, path: string = ''): Promise { const url = `/api/github/repository/${encodeURIComponent(repositoryId)}/structure${path ? `?path=${encodeURIComponent(path)}` : ''}` const res = await authApiClient.get(url) return res.data?.data as RepoStructureResponse } export interface FileContentResponse { file_info: { id: string filename: string file_extension?: string relative_path: string file_size_bytes?: number mime_type?: string is_binary?: boolean language_detected?: string line_count?: number char_count?: number } content: string | null preview?: string | null } export async function getRepositoryFileContent(repositoryId: string, filePath: string): Promise { const url = `/api/github/repository/${encodeURIComponent(repositoryId)}/file-content?file_path=${encodeURIComponent(filePath)}` const res = await authApiClient.get(url) return res.data?.data as FileContentResponse } export interface CommitSummaryResponse { last_commit: { hash: string short_hash: string author_name: string author_email: string committed_at: string message: string } | null total_commits: number } export async function getRepositoryCommitSummary(repositoryId: string): Promise { const url = `/api/github/repository/${encodeURIComponent(repositoryId)}/commit-summary` const res = await authApiClient.get(url) return res.data?.data as CommitSummaryResponse } export interface PathCommitResponse { hash: string short_hash: string author_name: string author_email: string committed_at: string message: string path: string } export async function getPathCommit(repositoryId: string, relPath: string): Promise { const url = `/api/github/repository/${encodeURIComponent(repositoryId)}/path-commit?path=${encodeURIComponent(relPath)}` const res = await authApiClient.get(url) return (res.data?.data as PathCommitResponse) || null } export interface CommitsListResponse { items: Array<{ hash: string short_hash: string author_name: string author_email: string committed_at: string message: string }> page: number limit: number total: number has_next: boolean } export async function getRepositoryCommits(repositoryId: string, opts?: { page?: number; limit?: number; path?: string }): Promise { const page = opts?.page ?? 1 const limit = opts?.limit ?? 20 const path = opts?.path ? `&path=${encodeURIComponent(opts.path)}` : '' const url = `/api/github/repository/${encodeURIComponent(repositoryId)}/commits?page=${page}&limit=${limit}${path}` const res = await authApiClient.get(url) return res.data?.data as CommitsListResponse } export interface ResolvePathInfo { repository_id: string local_path: string requested_file_path: string resolved_absolute_path: string | null exists: boolean is_directory: boolean } export async function resolveRepositoryPath(repositoryId: string, filePath: string): Promise { const url = `/api/github/repository/${encodeURIComponent(repositoryId)}/resolve-path?file_path=${encodeURIComponent(filePath)}` const res = await authApiClient.get(url) return res.data?.data as ResolvePathInfo } export interface AttachRepositoryResponse { success: boolean message?: string data?: T requires_auth?: boolean auth_url?: string auth_error?: boolean } export async function attachRepository(payload: AttachRepositoryPayload): Promise { // Add user_id as query fallback besides header for gateway caching/proxies const rawUser = (typeof window !== 'undefined') ? localStorage.getItem('codenuk_user') : null const userId = rawUser ? (JSON.parse(rawUser)?.id || null) : null const url = userId ? `/api/github/attach-repository?user_id=${encodeURIComponent(userId)}` : '/api/github/attach-repository' const response = await authApiClient.post(url, { ...payload, user_id: userId || payload.user_id }, { headers: { 'Content-Type': 'application/json', }, }) return response.data as AttachRepositoryResponse } export interface GitHubAuthStatusData { connected: boolean github_username?: string github_user_id?: string connected_at?: string scopes?: string[] requires_auth?: boolean auth_url?: string } export async function getGitHubAuthStatus(): Promise> { const rawUser = (typeof window !== 'undefined') ? localStorage.getItem('codenuk_user') : null const userId = rawUser ? (JSON.parse(rawUser)?.id || null) : null const url = userId ? `/api/github/auth/github/status?user_id=${encodeURIComponent(userId)}` : '/api/github/auth/github/status' const response = await authApiClient.get(url) return response.data as AttachRepositoryResponse } // -------- User repositories (UI-only helper) -------- export interface GitHubRepoSummary { id?: string | number full_name: string name: string owner?: { login?: string } | null description?: string | null visibility?: 'public' | 'private' stargazers_count?: number forks_count?: number language?: string | null updated_at?: string html_url?: string } // Tries backend gateway route first. If backend does not yet provide it, returns an empty list gracefully. export async function getUserRepositories(): Promise { try { const rawUser = (typeof window !== 'undefined') ? localStorage.getItem('codenuk_user') : null const userId = rawUser ? (JSON.parse(rawUser)?.id || null) : null // Prefer path param route; fallback to legacy query-based if gateway not updated const primaryUrl = userId ? `/api/github/user/${encodeURIComponent(userId)}/repositories` : '/api/github/user/repositories' let res try { res = await authApiClient.get(primaryUrl) } catch (e: any) { const fallbackUrl = userId ? `/api/github/user/repos?user_id=${encodeURIComponent(userId)}` : '/api/github/user/repos' res = await authApiClient.get(fallbackUrl) } const data = res?.data?.data || res?.data if (Array.isArray(data)) { // If data already looks like GitHubRepoSummary, return as-is if (data.length === 0) return [] const looksLike = (item: any) => item && (item.full_name || (item.name && item.owner)) if (looksLike(data[0])) return data as GitHubRepoSummary[] // Normalize rows coming from github_repositories table with parsed metadata/codebase_analysis const normalized = data.map((r: any) => { const md = r?.metadata || {} const owner = r?.owner_name || md?.owner?.login || (typeof md?.full_name === 'string' ? md.full_name.split('/')[0] : undefined) const name = r?.repository_name || md?.name || (typeof md?.full_name === 'string' ? md.full_name.split('/')[1] : undefined) || r?.repo const full = md?.full_name || (owner && name ? `${owner}/${name}` : r?.repository_url) return { id: r?.id, full_name: full, name: name, owner: owner ? { login: owner } : undefined, description: md?.description || null, visibility: md?.visibility || (r?.is_public ? 'public' : 'private'), stargazers_count: md?.stargazers_count || 0, forks_count: md?.forks_count || 0, language: md?.language || null, updated_at: md?.updated_at || r?.updated_at, html_url: md?.html_url || (full ? `https://github.com/${full}` : undefined), } as GitHubRepoSummary }) return normalized } return [] } catch (e: any) { // If endpoint not found or unauthorized, surface as empty for now (UI design requirement) const status = e?.response?.status if (status === 404 || status === 401) return [] return [] } }