Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -27,3 +27,63 @@ export const DB_CONFIG = {
|
||||
|
||||
export const JWT_SECRET = process.env.JWT_SECRET || "change-me-in-production";
|
||||
export const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || "7d";
|
||||
|
||||
function normalizeHostKey(value) {
|
||||
if (!value) return null;
|
||||
try {
|
||||
const url = new URL(value);
|
||||
return url.host.toLowerCase();
|
||||
} catch {
|
||||
return value.replace(/^[a-z]+:\/\//i, "").replace(/\/.*$/, "").trim().toLowerCase() || null;
|
||||
}
|
||||
}
|
||||
|
||||
function parseGiteaTokenMap(rawValue) {
|
||||
if (!rawValue) return {};
|
||||
const map = {};
|
||||
try {
|
||||
const parsed = typeof rawValue === "string" ? JSON.parse(rawValue) : rawValue;
|
||||
if (parsed && typeof parsed === "object") {
|
||||
for (const [key, token] of Object.entries(parsed)) {
|
||||
const host = normalizeHostKey(key);
|
||||
if (host && typeof token === "string" && token.trim()) {
|
||||
map[host] = token.trim();
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
} catch {
|
||||
// Fall through to comma-separated parsing.
|
||||
}
|
||||
|
||||
const segments = String(rawValue)
|
||||
.split(",")
|
||||
.map((segment) => segment.trim())
|
||||
.filter(Boolean);
|
||||
for (const segment of segments) {
|
||||
const [key, token] = segment.split("=").map((part) => part.trim());
|
||||
const host = normalizeHostKey(key);
|
||||
if (host && token) {
|
||||
map[host] = token;
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
const DEFAULT_GITEA_TOKEN = process.env.GITEA_TOKEN?.trim() || null;
|
||||
const GITEA_TOKENS = parseGiteaTokenMap(process.env.GITEA_TOKENS);
|
||||
|
||||
function getEnvTokenForHost(host) {
|
||||
if (!host) return null;
|
||||
const envKey = `GITEA_TOKEN_${host.replace(/[^A-Z0-9]/gi, "_").toUpperCase()}`;
|
||||
return process.env[envKey]?.trim() || null;
|
||||
}
|
||||
|
||||
export function getGiteaToken(baseUrl) {
|
||||
const host = normalizeHostKey(baseUrl);
|
||||
return (
|
||||
(host && (GITEA_TOKENS[host] || getEnvTokenForHost(host))) ||
|
||||
DEFAULT_GITEA_TOKEN ||
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ export async function resolveRepoDownload(repoEntry, requestedVersion = "latest"
|
||||
}
|
||||
|
||||
const repoInfo = await fetchRepo(normalizedEntry);
|
||||
if (repoInfo.isPrivate) {
|
||||
const error = new Error("Downloads niet beschikbaar voor private repositories.");
|
||||
error.meta = "PRIVATE_REPO";
|
||||
throw error;
|
||||
}
|
||||
const releases = await fetchReleases(normalizedEntry).catch(() => []);
|
||||
|
||||
let targetVersion = requestedVersion || "latest";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { readJsonFile } from "./storage.js";
|
||||
import { getCached, setCached } from "./cache.js";
|
||||
import { getGiteaToken } from "./config.js";
|
||||
|
||||
export function parseRepoEntry(entry) {
|
||||
if (typeof entry === "string") {
|
||||
@@ -51,6 +52,12 @@ async function fetchJson(url, cacheKey, opts = {}) {
|
||||
if (!opts.provider || opts.provider === "github") {
|
||||
headers.Accept = "application/vnd.github+json";
|
||||
}
|
||||
if (opts.provider === "gitea") {
|
||||
const token = opts.token || getGiteaToken(opts.baseUrl || url);
|
||||
if (token) {
|
||||
headers.Authorization = `token ${token}`;
|
||||
}
|
||||
}
|
||||
const response = await fetch(url, { headers });
|
||||
if (!response.ok) {
|
||||
throw new Error(`${opts.provider || "git"} request failed for ${url}`);
|
||||
@@ -76,7 +83,7 @@ export async function fetchRepo(entry) {
|
||||
let data;
|
||||
if (provider === "gitea") {
|
||||
const url = `${baseUrl.replace(/\/$/, "")}/api/v1/repos/${ownerRepo}`;
|
||||
data = await fetchJson(url, `repo-raw:${provider}:${ownerRepo}`, { provider });
|
||||
data = await fetchJson(url, `repo-raw:${provider}:${ownerRepo}`, { provider, baseUrl });
|
||||
const mapped = {
|
||||
fullName: data.full_name || `${ownerRepo}`,
|
||||
name: data.name || ownerRepo.split("/")[1] || ownerRepo,
|
||||
@@ -90,13 +97,16 @@ export async function fetchRepo(entry) {
|
||||
topics: data.topics || [],
|
||||
provider,
|
||||
ownerRepo,
|
||||
baseUrl
|
||||
baseUrl,
|
||||
isPrivate: Boolean(data.private)
|
||||
};
|
||||
setCached(cacheKey, mapped);
|
||||
return mapped;
|
||||
}
|
||||
|
||||
data = await fetchJson(`https://api.github.com/repos/${ownerRepo}`, `repo-raw:github:${ownerRepo}`, { provider: "github" });
|
||||
data = await fetchJson(`https://api.github.com/repos/${ownerRepo}`, `repo-raw:github:${ownerRepo}`, {
|
||||
provider: "github"
|
||||
});
|
||||
const mapped = {
|
||||
fullName: data.full_name,
|
||||
name: data.name,
|
||||
@@ -110,7 +120,8 @@ export async function fetchRepo(entry) {
|
||||
topics: data.topics || [],
|
||||
provider,
|
||||
ownerRepo,
|
||||
baseUrl: "https://github.com"
|
||||
baseUrl: "https://github.com",
|
||||
isPrivate: Boolean(data.private)
|
||||
};
|
||||
setCached(cacheKey, mapped);
|
||||
return mapped;
|
||||
@@ -131,7 +142,14 @@ export async function fetchManifest(entry, defaultBranch) {
|
||||
} else {
|
||||
url = `https://raw.githubusercontent.com/${ownerRepo}/${branch}/manifest.json`;
|
||||
}
|
||||
const response = await fetch(url, { headers: { "User-Agent": "siti-plugin-repo" } });
|
||||
const headers = { "User-Agent": "siti-plugin-repo" };
|
||||
if (provider === "gitea") {
|
||||
const token = getGiteaToken(baseUrl);
|
||||
if (token) {
|
||||
headers.Authorization = `token ${token}`;
|
||||
}
|
||||
}
|
||||
const response = await fetch(url, { headers });
|
||||
if (response.ok) {
|
||||
const manifest = await response.json().catch(() => null);
|
||||
setCached(cacheKey, manifest);
|
||||
@@ -145,7 +163,7 @@ export async function fetchReleases(entry) {
|
||||
const { provider, ownerRepo, baseUrl } = parseRepoEntry(entry);
|
||||
if (provider === "gitea") {
|
||||
const url = `${baseUrl.replace(/\/$/, "")}/api/v1/repos/${ownerRepo}/releases?limit=5`;
|
||||
const data = await fetchJson(url, `releases:${provider}:${ownerRepo}`, { provider });
|
||||
const data = await fetchJson(url, `releases:${provider}:${ownerRepo}`, { provider, baseUrl });
|
||||
return Array.isArray(data)
|
||||
? data.map((release) => ({
|
||||
tag: release.tag_name || release.name,
|
||||
@@ -175,7 +193,7 @@ export async function fetchCommits(entry) {
|
||||
const { provider, ownerRepo, baseUrl } = parseRepoEntry(entry);
|
||||
if (provider === "gitea") {
|
||||
const url = `${baseUrl.replace(/\/$/, "")}/api/v1/repos/${ownerRepo}/commits?limit=5`;
|
||||
const data = await fetchJson(url, `commits:${provider}:${ownerRepo}`, { provider });
|
||||
const data = await fetchJson(url, `commits:${provider}:${ownerRepo}`, { provider, baseUrl });
|
||||
return Array.isArray(data)
|
||||
? data.map((commit) => ({
|
||||
sha: commit.sha,
|
||||
|
||||
Reference in New Issue
Block a user