Files
Webklar-Kundenbereich/server/services/giteaClient.js
T

72 lines
2.3 KiB
JavaScript

import { config } from '../config.js'
/** Zeitlimit fuer jeden Gitea-API-Aufruf, in ms (ueberschreibbar via `GITEA_TIMEOUT_MS`, s. config.js). */
const GITEA_TIMEOUT_MS = config.gitea.timeoutMs
/**
* Baut die Authorization-/Content-Type-Header fuer einen Gitea-API-Aufruf.
* Wirft, wenn GITEA_API_TOKEN nicht gesetzt ist.
*/
function giteaHeaders() {
if (!config.gitea.apiToken) {
throw new Error('GITEA_API_TOKEN fehlt in .env')
}
return {
Authorization: `token ${config.gitea.apiToken}`,
'Content-Type': 'application/json',
}
}
/**
* Ruft `${config.gitea.baseUrl}/api/v1<path>` auf und liefert die geparste JSON-Antwort
* (oder null ohne Body). Eine Nicht-2xx-Antwort wirft eine Error mit .status; ein 409
* "same name already exists" wird in die deutsche Meldung uebersetzt (Subdomain-/Repo-Name).
* Bricht nach `GITEA_TIMEOUT_MS` ab (Standard 30 s); der Abbruch wirft eine Error OHNE .status,
* damit repoMove/projectAssignment ihn wie "Gitea nicht erreichbar" einordnen.
*/
export async function giteaFetch(path, options = {}) {
let response
try {
response = await fetch(`${config.gitea.baseUrl}/api/v1${path}`, {
...options,
headers: { ...giteaHeaders(), ...options.headers },
signal: options.signal || AbortSignal.timeout(GITEA_TIMEOUT_MS),
})
} catch (err) {
if (err?.name === 'TimeoutError' || err?.name === 'AbortError') {
throw new Error(`Gitea antwortet nicht (Zeitlimit ${Math.round(GITEA_TIMEOUT_MS / 1000)} s)`)
}
throw err
}
const text = await response.text()
let data = null
if (text) {
try {
data = JSON.parse(text)
} catch {
data = { message: text }
}
}
if (!response.ok) {
let message = data?.message || `Gitea ${response.status}`
if (response.status === 409 && /same name already exists/i.test(message)) {
message = 'Ein Gitea-Repository mit diesem Namen existiert bereits. Bitte einen anderen Subdomain-/Repo-Namen w�hlen.'
}
const error = new Error(message)
error.status = response.status
throw error
}
return data
}
/**
* Zerlegt "owner/repo" in [owner, repo]. Reines String-Splitting ohne Validierung -
* fuer nicht "owner/repo"-foermige Eingaben ist das Ergebnis entsprechend kurz/lang.
*/
export function splitRepo(fullName) {
return String(fullName || '').split('/')
}