feat: establish NekoNest Cloud control and relay

This commit is contained in:
2026-08-12 23:25:43 +08:00
commit f27606b709
222 changed files with 71456 additions and 0 deletions
+106
View File
@@ -0,0 +1,106 @@
import type { Metadata } from "next";
import Link from "next/link";
import { PublicShell, StatusPill } from "../components/Shells";
import {
checksumVerificationCommand,
getDaemonReleaseState,
} from "../daemon-release";
export const dynamic = "force-dynamic";
export const metadata: Metadata = {
title: "下载主机端 daemon",
description: "下载并核验用于 NekoNest Cloud 免费公测的 Windows 或 Linux 主机端 daemon。",
};
const unavailableCopy = {
not_configured: {
title: "兼容 Cloud 的公开构建尚未上架。",
body: "下载清单还没有同时配置兼容版本、三个平台包和各自 SHA-256,因此入口保持关闭。闭测参与者可以继续使用单独提供并完成核验的构建。",
},
invalid_config: {
title: "下载清单未通过安全校验。",
body: "版本、HTTPS 下载地址或 SHA-256 有一项不完整。修复前不会把用户送到不确定的二进制文件。",
},
incompatible_version: {
title: "现有发布版本不兼容 Cloud 接入。",
body: "下载入口只接受实现控制面激活交接的 daemon。旧版仍可用于自托管,但不会作为 Cloud 客户端展示。",
},
} as const;
export default async function DownloadPage() {
const release = await getDaemonReleaseState();
return (
<PublicShell>
<div className="public-page download-page">
<header className="download-hero">
<StatusPill tone={release.available ? "good" : "warn"}>
{release.available ? `CLOUD DAEMON v${release.version}` : "DOWNLOAD GATED"}
</StatusPill>
<h1>{release.available ? "下载、核验,再连接。" : unavailableCopy[release.reason].title}</h1>
<p>
{release.available
? "选择主机平台,下载固定版本压缩包,并在解压和运行前核对 SHA-256。主机无需开放入站端口。"
: unavailableCopy[release.reason].body}
</p>
<small>Cloud v{release.minimumVersion} · macOS </small>
</header>
{release.available ? (
<>
<section className="download-section" aria-labelledby="download-platform-title">
<div className="download-heading">
<span className="eyebrow">CHOOSE PLATFORM / </span>
<h2 id="download-platform-title"></h2>
<p>Linux <code>uname -m</code> Windows x64</p>
</div>
<div className="download-grid">
{release.assets.map((asset) => (
<article className="download-card" key={`${asset.platform}-${asset.architecture}`}>
<span className="download-platform">{asset.platform === "windows" ? "WINDOWS" : "LINUX"}</span>
<h3>{asset.label}</h3>
<code className="download-filename">{asset.filename}</code>
<a className="button button-primary" href={asset.downloadUrl} rel="noopener noreferrer"> v{release.version}</a>
<div className="checksum-block">
<strong></strong>
<code>{asset.sha256}</code>
</div>
<details>
<summary></summary>
<pre><code>{checksumVerificationCommand(asset)}</code></pre>
</details>
</article>
))}
</div>
</section>
<section className="download-proof">
<div>
<span className="eyebrow">VERIFY THE RELEASE / </span>
<h2></h2>
<p>SHA-256 线 Windows Authenticode </p>
</div>
<div className="download-proof-actions">
<a className="button button-secondary" href={release.checksumsUrl} rel="noopener noreferrer"> checksums.txt</a>
<a className="button button-secondary" href={release.releasePageUrl} rel="noopener noreferrer"> v{release.version} </a>
<Link className="button button-primary" href="/dashboard/hosts/new"></Link>
</div>
</section>
</>
) : (
<section className="download-gated" aria-labelledby="download-gated-title">
<div>
<span className="eyebrow">FAIL CLOSED / </span>
<h2 id="download-gated-title"></h2>
<p>Release Cloud HTTPS SHA-256 </p>
</div>
<div className="download-gated-actions">
<a className="button button-secondary" href="https://github.com/klarkxy/nekonest/releases" rel="noopener noreferrer"></a>
<Link className="button button-primary" href="/readiness"></Link>
</div>
</section>
)}
</div>
</PublicShell>
);
}