Files
Fractured/tools/fractured-launcher-electron/lib/gitea-release.js
T
Docker Build c1f7eaa153 fix(launcher): clearer fetch errors for Gitea TLS/DNS (fetch failed)
- fetchOrThrow wraps global fetch with TLS/DNS/refused hints + URL (sanitized).
- Use in gitea-release, github paths; fetchToFile already benefits.
- README checklist for sync Wow.exe fetch failed; version 1.0.5.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 21:46:48 -05:00

108 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
const { downloadBodyToFile, fetchOrThrow } = require('./http-download');
function normalizeGiteaBaseUrl(raw) {
let b = String(raw || '').trim().replace(/\/+$/, '');
if (!b) return '';
if (!/^https?:\/\//i.test(b)) b = `https://${b}`;
return b;
}
function giteaApiBase(cfg) {
const base = normalizeGiteaBaseUrl(cfg.gitea.base_url);
return `${base}/api/v1`;
}
function giteaToken(cfg) {
const name = cfg.gitea && cfg.gitea.token_env;
if (name && process.env[name]) return String(process.env[name]).trim();
return String(process.env.GITEA_TOKEN || '').trim();
}
function giteaHeaders(token, json = false) {
const h = { 'User-Agent': 'Fractured-Launcher-Electron' };
if (json) h.Accept = 'application/json';
if (token) h.Authorization = `token ${token}`;
return h;
}
function useGiteaReleases(cfg) {
const g = cfg.gitea;
if (!g) return false;
return !!(String(g.base_url || '').trim() && String(g.owner || '').trim() && String(g.repo || '').trim());
}
async function downloadGiteaReleaseAsset(cfg, assetName, destPath) {
const api = giteaApiBase(cfg);
const { owner, repo } = cfg.gitea;
const tag = (cfg.gitea.release_tag || 'latest').trim() || 'latest';
const token = giteaToken(cfg);
let listUrl;
if (tag.toLowerCase() === 'latest') {
listUrl = `${api}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/latest`;
} else {
listUrl = `${api}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/tags/${encodeURIComponent(tag)}`;
}
const res = await fetchOrThrow(listUrl, { headers: giteaHeaders(token, true) });
const text = await res.text();
if (!res.ok) {
let hint = '';
if (res.status === 404) hint = ' (wrong tag / no release / check base_url owner repo)';
if (res.status === 401 || res.status === 403) hint = ' (set GITEA_TOKEN or gitea.token_env)';
throw new Error(`Gitea release ${res.status}${hint}: ${text.slice(0, 600)}`);
}
const rel = JSON.parse(text);
const list = rel.attachments || rel.assets || [];
let downloadUrl = '';
for (const a of list) {
if (a.name !== assetName) continue;
downloadUrl = a.browser_download_url || a.download_url || '';
break;
}
if (!downloadUrl) {
const names = list.map((x) => x.name).filter(Boolean);
throw new Error(`Gitea release asset "${assetName}" not found; attachments: ${names.join(', ') || '(none)'}`);
}
const h = { Accept: 'application/octet-stream' };
if (token) h.Authorization = `token ${token}`;
const dl = await fetchOrThrow(downloadUrl, { headers: h, redirect: 'follow' });
await downloadBodyToFile(dl, destPath);
}
/**
* Base URL for electron-updater generic provider (expects latest.yml under this path).
* Matches Giteas pattern: …/owner/repo/releases/download/{tag}/latest.yml
*/
async function getGiteaUpdaterFeedBase(cfg) {
if (!useGiteaReleases(cfg)) return null;
const api = giteaApiBase(cfg);
const { owner, repo } = cfg.gitea;
const tag = (cfg.gitea.release_tag || 'latest').trim() || 'latest';
const token = giteaToken(cfg);
let listUrl;
if (tag.toLowerCase() === 'latest') {
listUrl = `${api}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/latest`;
} else {
listUrl = `${api}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/tags/${encodeURIComponent(tag)}`;
}
const res = await fetchOrThrow(listUrl, { headers: giteaHeaders(token, true) });
if (!res.ok) return null;
const rel = await res.json();
const tagName = rel.tag_name;
if (!tagName || typeof tagName !== 'string') return null;
const root = normalizeGiteaBaseUrl(cfg.gitea.base_url);
const url = `${root}/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/download/${encodeURIComponent(tagName)}/`;
return { url, token };
}
module.exports = {
downloadGiteaReleaseAsset,
giteaToken,
useGiteaReleases,
getGiteaUpdaterFeedBase,
};