Split monolithic index.ts (~1400 lines) into modular structure: - config.ts: Server configuration and constants - db/: Database initialization, migrations, and seeds - routes/: API handlers by domain (themes, canvas, components, etc.) - services/: Terminal WebSocket server - utils/: CORS helpers Entry point now only coordinates initialization.
131 lines
3.6 KiB
TypeScript
131 lines
3.6 KiB
TypeScript
import { jsonResponse, errorResponse } from '../utils/cors'
|
|
|
|
export async function handleGiteaRepo(req: Request) {
|
|
const body = await req.json()
|
|
const { giteaUrl, username, password, owner, repo } = body
|
|
|
|
if (!giteaUrl || !username || !password || !owner || !repo) {
|
|
return errorResponse('Missing required fields', 400)
|
|
}
|
|
|
|
try {
|
|
const auth = Buffer.from(`${username}:${password}`).toString('base64')
|
|
|
|
// Get repo info
|
|
const repoRes = await fetch(`${giteaUrl}/api/v1/repos/${owner}/${repo}`, {
|
|
headers: { 'Authorization': `Basic ${auth}` }
|
|
})
|
|
|
|
if (!repoRes.ok) {
|
|
if (repoRes.status === 401) {
|
|
return errorResponse('Invalid credentials', 401)
|
|
}
|
|
if (repoRes.status === 404) {
|
|
return errorResponse('Repository not found', 404)
|
|
}
|
|
throw new Error('Failed to connect to Gitea')
|
|
}
|
|
|
|
const repoData = await repoRes.json()
|
|
|
|
// Get branches
|
|
const branchesRes = await fetch(`${giteaUrl}/api/v1/repos/${owner}/${repo}/branches`, {
|
|
headers: { 'Authorization': `Basic ${auth}` }
|
|
})
|
|
|
|
let branches = ['main']
|
|
if (branchesRes.ok) {
|
|
const branchesData = await branchesRes.json()
|
|
branches = branchesData.map((b: any) => b.name)
|
|
}
|
|
|
|
return jsonResponse({
|
|
repo: {
|
|
name: repoData.name,
|
|
description: repoData.description,
|
|
default_branch: repoData.default_branch,
|
|
stars_count: repoData.stars_count,
|
|
forks_count: repoData.forks_count,
|
|
owner: { login: repoData.owner?.login || owner }
|
|
},
|
|
branches
|
|
})
|
|
} catch (e: any) {
|
|
return errorResponse(e.message, 500)
|
|
}
|
|
}
|
|
|
|
export async function handleGiteaTree(req: Request) {
|
|
const body = await req.json()
|
|
const { giteaUrl, username, password, owner, repo, branch, path } = body
|
|
|
|
try {
|
|
const auth = Buffer.from(`${username}:${password}`).toString('base64')
|
|
const apiPath = path
|
|
? `${giteaUrl}/api/v1/repos/${owner}/${repo}/contents/${path}?ref=${branch}`
|
|
: `${giteaUrl}/api/v1/repos/${owner}/${repo}/contents?ref=${branch}`
|
|
|
|
const res = await fetch(apiPath, {
|
|
headers: { 'Authorization': `Basic ${auth}` }
|
|
})
|
|
|
|
if (!res.ok) {
|
|
throw new Error('Failed to load tree')
|
|
}
|
|
|
|
const data = await res.json()
|
|
const items = Array.isArray(data) ? data : [data]
|
|
|
|
const tree = items
|
|
.map((item: any) => ({
|
|
name: item.name,
|
|
path: item.path,
|
|
type: item.type === 'dir' ? 'dir' : 'file',
|
|
children: item.type === 'dir' ? [] : undefined
|
|
}))
|
|
.sort((a: any, b: any) => {
|
|
if (a.type !== b.type) return a.type === 'dir' ? -1 : 1
|
|
return a.name.localeCompare(b.name)
|
|
})
|
|
|
|
return jsonResponse({ tree })
|
|
} catch (e: any) {
|
|
return errorResponse(e.message, 500)
|
|
}
|
|
}
|
|
|
|
export async function handleGiteaFile(req: Request) {
|
|
const body = await req.json()
|
|
const { giteaUrl, username, password, owner, repo, branch, path } = body
|
|
|
|
try {
|
|
const auth = Buffer.from(`${username}:${password}`).toString('base64')
|
|
|
|
const res = await fetch(
|
|
`${giteaUrl}/api/v1/repos/${owner}/${repo}/contents/${path}?ref=${branch}`,
|
|
{ headers: { 'Authorization': `Basic ${auth}` } }
|
|
)
|
|
|
|
if (!res.ok) {
|
|
throw new Error('Failed to load file')
|
|
}
|
|
|
|
const data = await res.json()
|
|
|
|
// Decode base64 content
|
|
let content = ''
|
|
if (data.content) {
|
|
content = Buffer.from(data.content, 'base64').toString('utf-8')
|
|
}
|
|
|
|
return jsonResponse({
|
|
content,
|
|
encoding: data.encoding,
|
|
size: data.size,
|
|
sha: data.sha
|
|
})
|
|
} catch (e: any) {
|
|
return errorResponse(e.message, 500)
|
|
}
|
|
}
|