gitApi.ts

 1// REST API client for git repository browsing.
 2// Endpoints are served by the Go backend at /api/git/*.
 3
 4export interface GitRef {
 5  name: string       // full ref: "refs/heads/main"
 6  shortName: string  // "main"
 7  type: 'branch' | 'tag'
 8  hash: string
 9  isDefault: boolean
10}
11
12export interface GitTreeEntry {
13  name: string
14  type: 'tree' | 'blob'
15  hash: string
16  mode: string
17  // Last commit touching this entry (may be absent if expensive to compute)
18  lastCommit?: {
19    hash: string
20    shortHash: string
21    message: string
22    authorName: string
23    date: string
24  }
25}
26
27export interface GitBlob {
28  path: string
29  content: string   // UTF-8 text; empty string when isBinary is true
30  size: number
31  isBinary: boolean
32}
33
34export interface GitCommit {
35  hash: string
36  shortHash: string
37  message: string
38  authorName: string
39  authorEmail: string
40  date: string
41  parents: string[]
42}
43
44export interface GitCommitDetail extends GitCommit {
45  fullMessage: string
46  files: Array<{
47    path: string
48    oldPath?: string
49    status: 'added' | 'modified' | 'deleted' | 'renamed'
50  }>
51}
52
53// ── Fetch helpers ─────────────────────────────────────────────────────────────
54
55async function get<T>(path: string, params: Record<string, string> = {}): Promise<T> {
56  const search = new URLSearchParams(params).toString()
57  const url = `/api/git${path}${search ? `?${search}` : ''}`
58  const res = await fetch(url)
59  if (!res.ok) {
60    const text = await res.text().catch(() => res.statusText)
61    throw new Error(text || res.statusText)
62  }
63  return res.json()
64}
65
66// ── API calls ─────────────────────────────────────────────────────────────────
67
68export function getRefs(): Promise<GitRef[]> {
69  return get('/refs')
70}
71
72export function getTree(ref: string, path: string): Promise<GitTreeEntry[]> {
73  return get('/tree', { ref, path })
74}
75
76export function getBlob(ref: string, path: string): Promise<GitBlob> {
77  return get('/blob', { ref, path })
78}
79
80export function getCommits(
81  ref: string,
82  opts: { path?: string; limit?: number; after?: string } = {},
83): Promise<GitCommit[]> {
84  const params: Record<string, string> = { ref, limit: String(opts.limit ?? 20) }
85  if (opts.path) params.path = opts.path
86  if (opts.after) params.after = opts.after
87  return get('/commits', params)
88}
89
90export function getCommit(hash: string): Promise<GitCommitDetail> {
91  return get('/commit', { hash })
92}