fix: 按 Halo 应用市场审核意见整改外部资源与隐私(v1.2.5 修订)
- 默认零第三方自动请求:移除 21 个模板的 preconnect/dns-prefetch、PrismJS+autoloader、qrcode-generator 及内置一言/IP 定位 API - 一言与代码高亮配色改为自托管;欢迎弹窗自定义 IP 接口改为 opt-in;微信分享改为复制链接;LightGallery 按 GPLv3 使用 - README 新增「外部资源与隐私」「验证与回归测试」章节,修正无效链接并补充字体 OFL 来源;同步 docs 与修正虚构的目录树 - friends 等 12 处 #strings.substring 加空值保护;logo 由两份 1.5MB 压缩去重为单份 146KB - 新增 pnpm audit:external 与打包前置合规审计;制品补齐 34 个 docs 文档与预览图
This commit is contained in:
1 parent
c0ad7331d4
commit
dda86294b0
36 files changed
+830
-236
No files matched your search
+48
-3
@@ -10,6 +10,7 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import zlib from "node:zlib";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { auditTemplates, auditReadmeLinks } from "./audit-external.mjs";
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
|
||||
@@ -131,11 +132,17 @@ const INCLUDE_ROOT = [
|
||||
"settings.yaml",
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
/* 上架说明引用的预览图必须真实存在于制品中(审核指南 4.6 / 2.2) */
|
||||
"WarmIsland Preview.webp",
|
||||
"pnpm-lock.yaml",
|
||||
"pnpm-workspace.yaml",
|
||||
];
|
||||
const INCLUDE_DIRS = ["templates"];
|
||||
const EXCLUDE_DIRS = new Set([".git", "node_modules", "src", "dist", "compat", ".astro"]);
|
||||
/* README 引用的 docs/*.md 也要随包分发,避免制品内出现死链 */
|
||||
const INCLUDE_DOCS = ["docs"];
|
||||
const EXCLUDE_DIRS = new Set([
|
||||
".git", "node_modules", "src", "dist", "compat", ".astro", ".vitepress",
|
||||
]);
|
||||
|
||||
/* ---------------- 构建产物前置校验 ----------------
|
||||
* templates/ 被 .gitignore 忽略,克隆仓库或清理工作区后默认不存在。
|
||||
@@ -173,14 +180,16 @@ for (const name of INCLUDE_ROOT) {
|
||||
}
|
||||
}
|
||||
|
||||
function walk(dir, prefix) {
|
||||
function walk(dir, prefix, opts = {}) {
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const abs = path.join(dir, entry.name);
|
||||
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
||||
if (entry.isDirectory()) {
|
||||
if (EXCLUDE_DIRS.has(entry.name)) continue;
|
||||
walk(abs, rel);
|
||||
walk(abs, rel, opts);
|
||||
} else {
|
||||
/* docs 只收 Markdown 源文件,不收 VitePress 构建产物 / 依赖 README */
|
||||
if (opts.mdOnly && !entry.name.endsWith(".md")) continue;
|
||||
entries.push({ name: rel, data: fs.readFileSync(abs), date: fs.statSync(abs).mtime });
|
||||
}
|
||||
}
|
||||
@@ -190,6 +199,10 @@ for (const dir of INCLUDE_DIRS) {
|
||||
const full = path.join(root, dir);
|
||||
if (fs.existsSync(full)) walk(full, dir);
|
||||
}
|
||||
for (const dir of INCLUDE_DOCS) {
|
||||
const full = path.join(root, dir);
|
||||
if (fs.existsSync(full)) walk(full, dir, { mdOnly: true });
|
||||
}
|
||||
|
||||
if (!entries.some((entry) => entry.name === "templates/index.html")) {
|
||||
fail("打包清单中缺少 templates/index.html");
|
||||
@@ -201,6 +214,38 @@ if (pkgVersion !== version) {
|
||||
fail(`版本号不一致:package.json=${pkgVersion},theme.yaml=${version}`);
|
||||
}
|
||||
|
||||
/* ---------------- 上架合规前置校验 ----------------
|
||||
* 1. 主题不得出现未披露的第三方自动请求 / 远程动态加载(审核指南 1.4 / 4.4.4)
|
||||
* 2. README 的相对链接必须在制品内真实存在(审核指南 4.6 / 2.2)
|
||||
* 3. logo 只保留一份压缩版,避免打包两份 1.5MB 大图
|
||||
*/
|
||||
const templateAudit = auditTemplates(templatesDir);
|
||||
for (const problem of templateAudit.problems) {
|
||||
console.error(`[package] ${problem}`);
|
||||
}
|
||||
if (templateAudit.problems.length) {
|
||||
fail("外部资源审计未通过:模板仍存在第三方远程加载 / 预连接");
|
||||
}
|
||||
|
||||
const linkAudit = auditReadmeLinks(new Set(entries.map((entry) => entry.name)));
|
||||
for (const problem of linkAudit.problems) {
|
||||
console.error(`[package] ${problem}`);
|
||||
}
|
||||
if (linkAudit.problems.length) {
|
||||
fail("README 存在指向制品中不存在文件的相对链接");
|
||||
}
|
||||
|
||||
if (fs.existsSync(path.join(templatesDir, "logo.png"))) {
|
||||
fail("templates/logo.png 仍存在:应只保留压缩后的 templates/assets/logo.png");
|
||||
}
|
||||
const logoFile = path.join(templatesDir, "assets", "logo.png");
|
||||
if (fs.existsSync(logoFile) && fs.statSync(logoFile).size > 300 * 1024) {
|
||||
fail("templates/assets/logo.png 超过 300KB,请先压缩再打包");
|
||||
}
|
||||
console.log(
|
||||
`[package] 合规审计通过(${templateAudit.htmlCount} 个模板、${linkAudit.checked} 个相对链接、logo 单份压缩)`
|
||||
);
|
||||
|
||||
const outFile = path.join(root, "dist", `warm-island-${version}.zip`);
|
||||
buildZip(entries, outFile);
|
||||
|
||||
|
||||
Reference in new issue
Block a user