fix(mindspace): 公开页上传图片物化到 static 路径供转发访问

Finish 同步与首次访问时将私有资产 API 图片复制到 public/.tmp-images,
避免其他用户转发链接后因无登录态无法加载页面内图片。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-07-06 17:03:47 +08:00
parent 1077dd9b97
commit 0ae7a6a677
5 changed files with 194 additions and 2 deletions
+50
View File
@@ -50,6 +50,7 @@ export async function materializePrivateAssetsInWorkspaceHtml({
htmlRelativePath,
writeBack = false,
}) {
PRIVATE_ASSET_URL_PATTERN.lastIndex = 0;
const matches = [...String(html).matchAll(PRIVATE_ASSET_URL_PATTERN)];
if (matches.length === 0) {
return { html, count: 0, changed: false };
@@ -106,6 +107,55 @@ export async function materializePrivateAssetsInWorkspaceHtml({
return { html: result, count, changed: true };
}
export function htmlReferencesPrivateAssets(html) {
PRIVATE_ASSET_URL_PATTERN.lastIndex = 0;
const found = PRIVATE_ASSET_URL_PATTERN.test(String(html ?? ''));
PRIVATE_ASSET_URL_PATTERN.lastIndex = 0;
return found;
}
export async function materializePrivateAssetsInPublicHtmlFiles({
pool,
storageRoot,
h5Root,
userId,
publishDir,
relativePaths = [],
}) {
const materialized = [];
const skipped = [];
const uniquePaths = [...new Set(relativePaths)].filter(Boolean);
for (const htmlRelativePath of uniquePaths) {
const htmlPath = path.join(publishDir, htmlRelativePath);
let html;
try {
html = await fs.readFile(htmlPath, 'utf8');
} catch {
skipped.push(htmlRelativePath);
continue;
}
if (!htmlReferencesPrivateAssets(html)) {
skipped.push(htmlRelativePath);
continue;
}
const result = await materializePrivateAssetsInWorkspaceHtml({
pool,
storageRoot,
h5Root,
userId,
html,
htmlRelativePath,
writeBack: true,
});
if (result.changed) {
materialized.push({ relativePath: htmlRelativePath, count: result.count });
} else {
skipped.push(htmlRelativePath);
}
}
return { materialized, skipped };
}
export async function repairMissingHtmlAssetReferences({ pool, userId, sourceContent, html }) {
const collectIds = (text) => [
...new Set([...String(text).matchAll(PRIVATE_ASSET_URL_PATTERN)].map((match) => match[1])),