2026-07-11 19:20:17 +08:00
|
|
|
|
import { NextResponse } from "next/server";
|
2026-09-05 19:52:54 +08:00
|
|
|
|
import {
|
|
|
|
|
|
fetchReleases,
|
|
|
|
|
|
pickBetaRelease,
|
|
|
|
|
|
pickAsset,
|
|
|
|
|
|
buildDownloadUrl,
|
|
|
|
|
|
isBetaRelease,
|
|
|
|
|
|
RELEASES_PAGE,
|
|
|
|
|
|
} from "@/lib/github-releases";
|
2026-07-11 19:20:17 +08:00
|
|
|
|
|
2026-08-31 12:01:41 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 预览版(Beta)发布信息接口
|
|
|
|
|
|
*
|
|
|
|
|
|
* 数据源优先级:
|
2026-09-05 19:52:54 +08:00
|
|
|
|
* 1. GitHub Releases API(直连 -> 镜像)—— 主源,自动识别最新预览版
|
|
|
|
|
|
* 2. 旧静态源 version.json —— 兜底(同时提供 Beta 协议 licence 文本)
|
2026-08-31 12:01:41 +08:00
|
|
|
|
*
|
2026-09-05 19:52:54 +08:00
|
|
|
|
* 返回:
|
|
|
|
|
|
* 顶层字段 = 最新预览版(licence 从旧静态源补充,下载需同意协议)
|
|
|
|
|
|
* versions = 历史预览版列表(新 -> 旧,按资产匹配平台;无 licence 数据,直接下载)
|
2026-08-31 12:01:41 +08:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
const LEGACY_URL =
|
|
|
|
|
|
"https://koring-launcher-file-api.lenjing.cloud/launcher/beta/version.json";
|
|
|
|
|
|
|
2026-09-05 19:52:54 +08:00
|
|
|
|
const HISTORY_LIMIT = 10;
|
2026-08-31 12:01:41 +08:00
|
|
|
|
|
|
|
|
|
|
const EMPTY_LICENCE = { isNeedAgreat: "false", title: "", text: "", liceURL: "" };
|
|
|
|
|
|
|
|
|
|
|
|
const EMPTY_APPS = {
|
|
|
|
|
|
windows: { isNoVersion: "true", licence: EMPTY_LICENCE, DownlodeURL: "" },
|
|
|
|
|
|
macos: { isNoVersion: "true", licence: EMPTY_LICENCE, DownlodeURL: "" },
|
|
|
|
|
|
linux: { isNoVersion: "true", licence: EMPTY_LICENCE, DownlodeURL: "" },
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 简单内存缓存(TTL 15 分钟),避免频繁打 GitHub API / 限流代理
|
|
|
|
|
|
const CACHE_TTL = 15 * 60 * 1000;
|
|
|
|
|
|
const cache = new Map<string, { time: number; value: unknown }>();
|
|
|
|
|
|
|
2026-09-05 19:52:54 +08:00
|
|
|
|
function sortDesc(releases: any[]) {
|
|
|
|
|
|
return [...(releases || [])].sort((a, b) =>
|
|
|
|
|
|
String(b.published_at || b.created_at || "").localeCompare(
|
|
|
|
|
|
String(a.published_at || a.created_at || "")
|
|
|
|
|
|
)
|
2026-08-31 12:01:41 +08:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-05 19:52:54 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 平台信息(DownlodeURL 为下载直链)
|
|
|
|
|
|
* licenceFor:给某平台提供 licence(最新版用旧源协议文本,历史版用空 = 无需同意)
|
|
|
|
|
|
*/
|
|
|
|
|
|
function buildPlatforms(release: any, licenceFor: (key: string) => any) {
|
|
|
|
|
|
const tag = String(release.tag_name || "");
|
2026-08-31 12:01:41 +08:00
|
|
|
|
const mk = (hit: any, key: string) => ({
|
|
|
|
|
|
isNoVersion: hit ? "false" : "true",
|
2026-09-05 19:52:54 +08:00
|
|
|
|
licence: licenceFor(key),
|
|
|
|
|
|
DownlodeURL: hit ? buildDownloadUrl(tag, hit.name) : "",
|
2026-08-31 12:01:41 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
2026-09-05 19:52:54 +08:00
|
|
|
|
windows: mk(pickAsset(release, [/setup\.exe$/i, /\.exe$/i]), "windows"),
|
|
|
|
|
|
macos: mk(pickAsset(release, [/\.dmg$/i, /\.zip$/i, /\.pkg$/i]), "macos"),
|
|
|
|
|
|
linux: mk(
|
|
|
|
|
|
pickAsset(release, [/\.appimage$/i, /\.deb$/i, /\.rpm$/i, /\.tar\.gz$/i]),
|
|
|
|
|
|
"linux"
|
|
|
|
|
|
),
|
2026-08-31 12:01:41 +08:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-05 19:52:54 +08:00
|
|
|
|
function baseEntry(release: any) {
|
|
|
|
|
|
const tag = String(release.tag_name || "");
|
|
|
|
|
|
return {
|
|
|
|
|
|
version: tag.replace(/^v/i, ""),
|
|
|
|
|
|
builddate: release.published_at || release.created_at || "",
|
|
|
|
|
|
tag,
|
|
|
|
|
|
htmlUrl: release.html_url || `${RELEASES_PAGE}/tag/${tag}`,
|
|
|
|
|
|
releaseNotes: release.body || "",
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function buildGithubPayload(beta: any, legacy: any) {
|
|
|
|
|
|
// 最新预览版:licence 用旧静态源文本(保持原有"需同意 Beta 协议"体验)
|
|
|
|
|
|
const licenceSrc = legacy?.app || null;
|
2026-08-31 12:01:41 +08:00
|
|
|
|
return {
|
|
|
|
|
|
source: "github",
|
2026-09-05 19:52:54 +08:00
|
|
|
|
...baseEntry(beta),
|
|
|
|
|
|
app: buildPlatforms(beta, (key) => licenceSrc?.[key]?.licence ?? EMPTY_LICENCE),
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 历史预览版条目(无协议要求) */
|
|
|
|
|
|
function buildHistoryEntry(release: any) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
...baseEntry(release),
|
|
|
|
|
|
app: buildPlatforms(release, () => EMPTY_LICENCE),
|
2026-08-31 12:01:41 +08:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function buildLegacyPayload(legacy: any) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
source: "legacy",
|
|
|
|
|
|
version: String(legacy.version || ""),
|
|
|
|
|
|
builddate: String(legacy.builddate || ""),
|
|
|
|
|
|
app: legacy.app ?? EMPTY_APPS,
|
|
|
|
|
|
aboutversion: legacy.aboutversion,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export async function GET() {
|
|
|
|
|
|
const now = Date.now();
|
|
|
|
|
|
const cached = cache.get("beta");
|
|
|
|
|
|
if (cached && now - cached.time < CACHE_TTL) {
|
|
|
|
|
|
return NextResponse.json(cached.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 1) 主源:GitHub Releases API(直连 -> 镜像)
|
2026-09-05 19:52:54 +08:00
|
|
|
|
const releases = await fetchReleases();
|
2026-08-31 12:01:41 +08:00
|
|
|
|
|
|
|
|
|
|
// 2) 兜底源:旧静态 JSON(也用于补充 Beta 协议 licence)
|
2026-09-05 19:52:54 +08:00
|
|
|
|
let legacy: any = null;
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await fetch(LEGACY_URL, {
|
|
|
|
|
|
cache: "no-store",
|
|
|
|
|
|
signal: AbortSignal.timeout(15_000),
|
|
|
|
|
|
});
|
|
|
|
|
|
if (res.ok) legacy = await res.json();
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
legacy = null;
|
|
|
|
|
|
}
|
2026-08-31 12:01:41 +08:00
|
|
|
|
|
|
|
|
|
|
let payload: unknown;
|
|
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(releases) && releases.length > 0) {
|
|
|
|
|
|
const beta = pickBetaRelease(releases);
|
|
|
|
|
|
if (beta) {
|
2026-09-05 19:52:54 +08:00
|
|
|
|
const betaTag = String(beta.tag_name || "");
|
|
|
|
|
|
const history = sortDesc(releases)
|
|
|
|
|
|
.filter(
|
|
|
|
|
|
(r) =>
|
|
|
|
|
|
isBetaRelease(r) && String(r.tag_name || "") !== betaTag
|
|
|
|
|
|
)
|
|
|
|
|
|
.slice(0, HISTORY_LIMIT)
|
|
|
|
|
|
.map(buildHistoryEntry);
|
|
|
|
|
|
|
|
|
|
|
|
payload = {
|
|
|
|
|
|
...buildGithubPayload(beta, legacy),
|
|
|
|
|
|
versions: history,
|
|
|
|
|
|
};
|
2026-08-31 12:01:41 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
// GitHub 可达但没有任何预览版
|
|
|
|
|
|
payload = {
|
|
|
|
|
|
source: "github",
|
|
|
|
|
|
noRelease: true,
|
|
|
|
|
|
version: "",
|
|
|
|
|
|
builddate: "",
|
|
|
|
|
|
app: EMPTY_APPS,
|
2026-09-05 19:52:54 +08:00
|
|
|
|
versions: [],
|
2026-08-31 12:01:41 +08:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (legacy) {
|
|
|
|
|
|
payload = buildLegacyPayload(legacy);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return NextResponse.json(
|
|
|
|
|
|
{ error: "无法获取版本信息,请稍后重试" },
|
|
|
|
|
|
{ status: 502 }
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
cache.set("beta", { time: now, value: payload });
|
|
|
|
|
|
return NextResponse.json(payload);
|
2026-07-11 19:20:17 +08:00
|
|
|
|
}
|