feat: improve mindspace asset handling and local runtime paths

This commit is contained in:
john
2026-06-28 12:18:26 +08:00
parent 4a9bc710f1
commit ea19ffb5fa
36 changed files with 867 additions and 100 deletions
+59
View File
@@ -13,6 +13,8 @@ import {
extractStaticPageLinks,
findPublishHtml,
injectHtmlBaseHref,
materializePrivateAssetsInWorkspaceHtml,
repairMissingHtmlAssetReferences,
resolveClosestHtmlRelativePath,
resolveChatSaveAnalysis,
sanitizeMessageContentForSave,
@@ -185,3 +187,60 @@ test('resolveChatSaveAnalysis falls back to local html filename hints', async ()
assert.equal(result.analysis.contentMode, 'static_html');
assert.equal(result.resolvedHtml?.relativePath, 'public/welcome-v2.html');
});
test('materializePrivateAssetsInWorkspaceHtml copies images to public/.tmp-images', async () => {
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'mindspace-chat-save-materialize-'));
const storageRoot = path.join(root, 'storage');
const assetId = '11111111-1111-4111-8111-111111111111';
const userId = USER_ID;
const storageKey = `users/${userId}/assets/${assetId}/versions/v1`;
const sourcePath = path.join(storageRoot, storageKey);
await fs.mkdir(path.dirname(sourcePath), { recursive: true });
await fs.writeFile(sourcePath, Buffer.from([0xff, 0xd8, 0xff, 0xd9]));
const publishDir = path.join(root, 'MindSpace', userId, 'public');
await fs.mkdir(publishDir, { recursive: true });
const htmlRelativePath = 'public/look.html';
const htmlPath = path.join(root, 'MindSpace', userId, htmlRelativePath);
const html = `<!doctype html><img src="/api/mindspace/v1/assets/${assetId}/download?inline=1">`;
await fs.writeFile(htmlPath, html, 'utf8');
const pool = {
query: async () => [
[{ id: assetId, mime_type: 'image/jpeg', original_filename: 'hero.jpg', storage_key: storageKey }],
],
};
const result = await materializePrivateAssetsInWorkspaceHtml({
pool,
storageRoot,
h5Root: root,
userId,
html,
htmlRelativePath,
writeBack: true,
});
assert.equal(result.changed, true);
assert.match(result.html, /\.tmp-images\/11111111-1111-4111-8111-111111111111\.jpg/);
await fs.stat(path.join(publishDir, '.tmp-images', `${assetId}.jpg`));
});
test('repairMissingHtmlAssetReferences swaps invalid html asset ids from chat message', async () => {
const validId = '22222222-2222-4222-8222-222222222222';
const invalidId = '33333333-3333-4333-8333-333333333333';
const html = `<img src="/api/mindspace/v1/assets/${invalidId}/download?inline=1">`;
const sourceContent = `[图片1]: /api/mindspace/v1/assets/${validId}/download?inline=1`;
const pool = {
query: async (_sql, params) => [[{ id: validId }]],
};
const result = await repairMissingHtmlAssetReferences({
pool,
userId: USER_ID,
sourceContent,
html,
});
assert.equal(result.changed, true);
assert.match(result.html, new RegExp(validId));
assert.doesNotMatch(result.html, new RegExp(invalidId));
});