234 lines
8.2 KiB
TypeScript
234 lines
8.2 KiB
TypeScript
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<RepoStructureResponse> {
|
|
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<FileContentResponse> {
|
|
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<CommitSummaryResponse> {
|
|
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<PathCommitResponse | null> {
|
|
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<CommitsListResponse> {
|
|
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<ResolvePathInfo> {
|
|
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<T = unknown> {
|
|
success: boolean
|
|
message?: string
|
|
data?: T
|
|
requires_auth?: boolean
|
|
auth_url?: string
|
|
auth_error?: boolean
|
|
}
|
|
|
|
export async function attachRepository(payload: AttachRepositoryPayload): Promise<AttachRepositoryResponse> {
|
|
// 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<AttachRepositoryResponse<GitHubAuthStatusData>> {
|
|
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<GitHubAuthStatusData>
|
|
}
|
|
|
|
|
|
// -------- 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<GitHubRepoSummary[]> {
|
|
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 []
|
|
}
|
|
}
|
|
|