fix filename patch scope

This commit is contained in:
2026-05-20 01:57:22 +08:00
parent 03c56a20db
commit 35cd438018
8 changed files with 30 additions and 14 deletions

6
dist/SHA256SUMS vendored
View File

@@ -1,3 +1,3 @@
62d2a619dbade4a2fad0a9fbf4ff3389fed7afd9b5556b5d1e0a414d69ccd9dd reactive-resume-clean-install-20260520.zip
b737f2e75437c25e32760ca81532c27bfc0f5455e12afca14a3439af8b2851c1 reactive-resume-personal-direct-20260520.zip
c3414564cadd093e93b2bf9769bbb9eafc8e760cf98a216340516db2aea3007f reactive-resume-personal-qnap-nas-20260520.zip
4310b841d283d76465e8f7c53d630b24ad10e75ae5b6039399db1adcded8702e reactive-resume-clean-install-20260520.zip
c2a24e404fe47bf4c21c01d22fa21af0c86323ef246606fe7152ad293b46ab34 reactive-resume-personal-direct-20260520.zip
5d26c24423159df199b9c2263d02de64912d7c4f44f7e17bf5beef2d2d601e8f reactive-resume-personal-qnap-nas-20260520.zip

View File

@@ -1,3 +1,3 @@
62d2a619dbade4a2fad0a9fbf4ff3389fed7afd9b5556b5d1e0a414d69ccd9dd reactive-resume-clean-install-20260520.zip
b737f2e75437c25e32760ca81532c27bfc0f5455e12afca14a3439af8b2851c1 reactive-resume-personal-direct-20260520.zip
c3414564cadd093e93b2bf9769bbb9eafc8e760cf98a216340516db2aea3007f reactive-resume-personal-qnap-nas-20260520.zip
4310b841d283d76465e8f7c53d630b24ad10e75ae5b6039399db1adcded8702e reactive-resume-clean-install-20260520.zip
c2a24e404fe47bf4c21c01d22fa21af0c86323ef246606fe7152ad293b46ab34 reactive-resume-personal-direct-20260520.zip
5d26c24423159df199b9c2263d02de64912d7c4f44f7e17bf5beef2d2d601e8f reactive-resume-personal-qnap-nas-20260520.zip

Binary file not shown.

Binary file not shown.

View File

@@ -60,7 +60,7 @@ const assetsDir = process.env.ASSETS_DIR || path.join(outputDir, "public/assets"
const ssrDir = process.env.SSR_DIR || "";
const explicitSsrFile = process.env.SSR_FILE || "";
const serverIndexFile = process.env.SERVER_INDEX_FILE || path.join(outputDir, "server/index.mjs");
const filenameCacheBust = "rr-filename-title-20260520";
const filenameCacheBust = "rr-filename-title-20260520b";
const pdfCacheBust = "rr-glalie-layout-20260520";
const browserBufferPolyfill = "var Buffer=globalThis.Buffer??{isBuffer:()=>false,allocUnsafe:e=>new Uint8Array(e),alloc:e=>new Uint8Array(e)};/* rr-browser-buffer-polyfill */";
@@ -120,8 +120,11 @@ function replaceRegexOnce(source, regex, to) {
}
function patchFilenameBundle(file) {
if (!/^file-[A-Za-z0-9_-]+\.js$/.test(path.basename(file))) {
return false;
}
let source = read(file);
const replacement = 'function t(e,t){let n=(e||"resume").toString().trim()||"resume";return n=n.replace(/[\\\\/:*?"<>|]/g,"-").replace(/\\s+/g," ").replace(/\\.+$/,"").trim()||"resume",t&&n.toLowerCase().endsWith("."+t.toLowerCase())?n:`${n}${t?`.${t}`:""}`}';
const replacement = 'function t(e,t){let n=(e??"resume").toString().trim()||"resume",r=t==null?"":String(t).trim().replace(/^\\./,"");return n=n.replace(/[\\\\/:*?"<>|]/g,"-").replace(/\\s+/g," ").replace(/\\.+$/,"").trim()||"resume",r&&n.toLowerCase().endsWith("."+r.toLowerCase())?n:`${n}${r?`.${r}`:""}`}';
if (source.includes(replacement)) return true;
const start = source.indexOf("function t(");
@@ -139,7 +142,7 @@ function patchFilenameBundle(file) {
function patchSsr(source) {
source = source.replace(/\n\t\tname: "",\n\t\tdata: \{/, "\n\t\tname: resume.name,\n\t\tdata: {");
const filenameReplacement = `function generateFilename(prefix, extension) {\n\tlet filename = (prefix || "resume").toString().trim() || "resume";\n\tfilename = filename.replace(/[\\\\/:*?"<>|]/g, "-").replace(/\\s+/g, " ").replace(/\\.+$/, "").trim() || "resume";\n\treturn extension && filename.toLowerCase().endsWith(\`.\${extension.toLowerCase()}\`) ? filename : \`\${filename}\${extension ? \`.\${extension}\` : ""}\`;\n}`;
const filenameReplacement = `function generateFilename(prefix, extension) {\n\tlet filename = (prefix ?? "resume").toString().trim() || "resume";\n\tlet ext = extension == null ? "" : String(extension).trim().replace(/^\\./, "");\n\tfilename = filename.replace(/[\\\\/:*?"<>|]/g, "-").replace(/\\s+/g, " ").replace(/\\.+$/, "").trim() || "resume";\n\treturn ext && filename.toLowerCase().endsWith(\`.\${ext.toLowerCase()}\`) ? filename : \`\${filename}\${ext ? \`.\${ext}\` : ""}\`;\n}`;
if (!source.includes(filenameReplacement)) {
const slugifiedPattern = /function generateFilename\(prefix, extension\) \{\s*return `\$\{slugify\(prefix\)\}\$\{extension \? `\.\$\{extension\}` : ""\}`;\s*\}/;
if (slugifiedPattern.test(source)) {
@@ -211,8 +214,9 @@ function patchPublicPdf(source) {
const assetFiles = listJsFiles(assetsDir);
const filenameFiles = assetFiles
.filter((file) => {
if (!/^file-[A-Za-z0-9_-]+\.js$/.test(path.basename(file))) return false;
const source = read(file);
return source.includes("URL.createObjectURL") && source.includes(".download");
return source.includes("URL.createObjectURL") && source.includes(".download") && source.includes("revokeObjectURL");
})
.sort((a, b) => fs.statSync(a).size - fs.statSync(b).size);

View File

@@ -60,7 +60,7 @@ const assetsDir = process.env.ASSETS_DIR || path.join(outputDir, "public/assets"
const ssrDir = process.env.SSR_DIR || "";
const explicitSsrFile = process.env.SSR_FILE || "";
const serverIndexFile = process.env.SERVER_INDEX_FILE || path.join(outputDir, "server/index.mjs");
const filenameCacheBust = "rr-filename-title-20260520";
const filenameCacheBust = "rr-filename-title-20260520b";
const pdfCacheBust = "rr-glalie-layout-20260520";
const browserBufferPolyfill = "var Buffer=globalThis.Buffer??{isBuffer:()=>false,allocUnsafe:e=>new Uint8Array(e),alloc:e=>new Uint8Array(e)};/* rr-browser-buffer-polyfill */";
@@ -120,8 +120,11 @@ function replaceRegexOnce(source, regex, to) {
}
function patchFilenameBundle(file) {
if (!/^file-[A-Za-z0-9_-]+\.js$/.test(path.basename(file))) {
return false;
}
let source = read(file);
const replacement = 'function t(e,t){let n=(e||"resume").toString().trim()||"resume";return n=n.replace(/[\\\\/:*?"<>|]/g,"-").replace(/\\s+/g," ").replace(/\\.+$/,"").trim()||"resume",t&&n.toLowerCase().endsWith("."+t.toLowerCase())?n:`${n}${t?`.${t}`:""}`}';
const replacement = 'function t(e,t){let n=(e??"resume").toString().trim()||"resume",r=t==null?"":String(t).trim().replace(/^\\./,"");return n=n.replace(/[\\\\/:*?"<>|]/g,"-").replace(/\\s+/g," ").replace(/\\.+$/,"").trim()||"resume",r&&n.toLowerCase().endsWith("."+r.toLowerCase())?n:`${n}${r?`.${r}`:""}`}';
if (source.includes(replacement)) return true;
const start = source.indexOf("function t(");
@@ -139,7 +142,7 @@ function patchFilenameBundle(file) {
function patchSsr(source) {
source = source.replace(/\n\t\tname: "",\n\t\tdata: \{/, "\n\t\tname: resume.name,\n\t\tdata: {");
const filenameReplacement = `function generateFilename(prefix, extension) {\n\tlet filename = (prefix || "resume").toString().trim() || "resume";\n\tfilename = filename.replace(/[\\\\/:*?"<>|]/g, "-").replace(/\\s+/g, " ").replace(/\\.+$/, "").trim() || "resume";\n\treturn extension && filename.toLowerCase().endsWith(\`.\${extension.toLowerCase()}\`) ? filename : \`\${filename}\${extension ? \`.\${extension}\` : ""}\`;\n}`;
const filenameReplacement = `function generateFilename(prefix, extension) {\n\tlet filename = (prefix ?? "resume").toString().trim() || "resume";\n\tlet ext = extension == null ? "" : String(extension).trim().replace(/^\\./, "");\n\tfilename = filename.replace(/[\\\\/:*?"<>|]/g, "-").replace(/\\s+/g, " ").replace(/\\.+$/, "").trim() || "resume";\n\treturn ext && filename.toLowerCase().endsWith(\`.\${ext.toLowerCase()}\`) ? filename : \`\${filename}\${ext ? \`.\${ext}\` : ""}\`;\n}`;
if (!source.includes(filenameReplacement)) {
const slugifiedPattern = /function generateFilename\(prefix, extension\) \{\s*return `\$\{slugify\(prefix\)\}\$\{extension \? `\.\$\{extension\}` : ""\}`;\s*\}/;
if (slugifiedPattern.test(source)) {
@@ -211,8 +214,9 @@ function patchPublicPdf(source) {
const assetFiles = listJsFiles(assetsDir);
const filenameFiles = assetFiles
.filter((file) => {
if (!/^file-[A-Za-z0-9_-]+\.js$/.test(path.basename(file))) return false;
const source = read(file);
return source.includes("URL.createObjectURL") && source.includes(".download");
return source.includes("URL.createObjectURL") && source.includes(".download") && source.includes("revokeObjectURL");
})
.sort((a, b) => fs.statSync(a).size - fs.statSync(b).size);

View File

@@ -106,6 +106,11 @@ if grep -E 'Cannot find module|Buffer is not defined|Unexpected end of input' /t
cat /tmp/reactive-resume-direct.log >&2
fail "direct 包日志仍包含已知启动或前端错误"
fi
if docker exec "$PROJECT-reactive-resume-1" sh -lc 'APP_DIR=$(cat /tmp/reactive-resume-app-dir); grep -R -E "index-[A-Za-z0-9_-]+\\.js\\?v=rr-filename-title" "$APP_DIR/.output/public/assets" >/dev/null 2>&1'; then
fail "direct 包错误地给 index 主入口追加了 rr-filename-title 缓存标记"
fi
docker exec "$PROJECT-reactive-resume-1" sh -lc 'APP_DIR=$(cat /tmp/reactive-resume-app-dir); grep -R "String(t).trim().replace" "$APP_DIR/.output/public/assets"/file-*.js >/dev/null 2>&1' \
|| fail "direct 包未在 file-*.js 下载工具中应用文件名补丁"
log "离线检查 arm64/QNAP 镜像布局"
ARM64_DIGEST="$(
@@ -165,6 +170,9 @@ grep -R 'rr-browser-buffer-polyfill' "$ARM64_ASSETS_DIR" >/dev/null \
|| fail "arm64 public PDF bundle 未注入 Buffer polyfill"
grep -R -F 'replace(/[\\/:*?"<>|]/g' "$ARM64_ASSETS_DIR" >/dev/null \
|| fail "arm64 文件名 bundle 未改为按标题下载"
if grep -R -E "index-[A-Za-z0-9_-]+\\.js\\?v=rr-filename-title" "$ARM64_ASSETS_DIR" >/dev/null 2>&1; then
fail "arm64 补丁错误地给 index 主入口追加了 rr-filename-title 缓存标记"
fi
grep -q 'function generateFilename(prefix, extension)' "$ARM64_FILENAME_ENTRY" \
|| fail "arm64 server entry 未包含 generateFilename"
grep -F 'filename.replace(/[\\/:*?"<>|]/g' "$ARM64_FILENAME_ENTRY" >/dev/null \