fix: MindSpace remote sync, thumbnail fallback, and Plaza URL guards
Ensure page sync runs via pageSyncService in remote mode, fall back to workspace HTML when storage assets are missing, and prevent production Portal from linking to loopback Plaza URLs baked in at build time. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+52
-5
@@ -309,6 +309,45 @@ export function createPageService(pool, options = {}) {
|
||||
throw lastError ?? Object.assign(new Error('存储文件不存在'), { code: 'storage_not_found' });
|
||||
};
|
||||
|
||||
// REGRESSION GUARD: mindspace-page-sync-thumbnail — storage ENOENT 时回退读 workspace HTML
|
||||
const readPageContentWithWorkspaceFallback = async ({
|
||||
userId,
|
||||
storageKey,
|
||||
sourceSnapshotJson,
|
||||
pageType,
|
||||
}) => {
|
||||
let snapshot = {};
|
||||
try {
|
||||
snapshot = parseJsonColumn(sourceSnapshotJson);
|
||||
} catch {
|
||||
snapshot = {};
|
||||
}
|
||||
const workspaceHtmlRelativePath =
|
||||
pageType === 'html' ? snapshot.relative_path ?? null : null;
|
||||
const workspacePublishDir = workspaceHtmlRelativePath
|
||||
? await resolveWorkspacePublishDir(userId)
|
||||
: null;
|
||||
|
||||
try {
|
||||
const storagePath = await resolveReadableStoragePath(storageKey);
|
||||
return await fs.readFile(storagePath, 'utf8');
|
||||
} catch (error) {
|
||||
const storageMissing = error?.code === 'ENOENT' || error?.code === 'storage_not_found';
|
||||
if (!storageMissing || !workspacePublishDir || !workspaceHtmlRelativePath) {
|
||||
throw error;
|
||||
}
|
||||
const workspaceHtmlPath = path.join(workspacePublishDir, workspaceHtmlRelativePath);
|
||||
try {
|
||||
return await fs.readFile(workspaceHtmlPath, 'utf8');
|
||||
} catch (workspaceError) {
|
||||
if (workspaceError?.code === 'ENOENT') {
|
||||
throw error;
|
||||
}
|
||||
throw workspaceError;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const writeVersionContent = async (userId, assetId, versionId, content) => {
|
||||
const storageKey = path.posix.join(
|
||||
'users',
|
||||
@@ -668,7 +707,7 @@ export function createPageService(pool, options = {}) {
|
||||
|
||||
async function getPage(userId, pageId) {
|
||||
const [rows] = await pool.query(
|
||||
`SELECT p.*, c.category_code, pv.version_no, av.storage_key
|
||||
`SELECT p.*, c.category_code, pv.version_no, av.storage_key, pv.source_snapshot_json
|
||||
FROM h5_page_records p
|
||||
JOIN h5_space_categories c ON c.id = p.category_id AND c.user_id = p.user_id
|
||||
JOIN h5_page_versions pv ON pv.id = p.current_version_id
|
||||
@@ -679,8 +718,12 @@ export function createPageService(pool, options = {}) {
|
||||
);
|
||||
const row = rows[0];
|
||||
if (!row) throw pageError('页面不存在', 'page_not_found');
|
||||
const storagePath = await resolveReadableStoragePath(row.storage_key);
|
||||
const content = await fs.readFile(storagePath, 'utf8');
|
||||
const content = await readPageContentWithWorkspaceFallback({
|
||||
userId,
|
||||
storageKey: row.storage_key,
|
||||
sourceSnapshotJson: row.source_snapshot_json,
|
||||
pageType: row.page_type,
|
||||
});
|
||||
return pageResponse({ ...row, content });
|
||||
}
|
||||
|
||||
@@ -1265,8 +1308,12 @@ export function createPageService(pool, options = {}) {
|
||||
if (row.page_type !== 'html') {
|
||||
throw pageError('该页面不支持缩略图', 'thumbnail_not_supported');
|
||||
}
|
||||
const storagePath = await resolveReadableStoragePath(row.storage_key);
|
||||
const content = await fs.readFile(storagePath, 'utf8');
|
||||
const content = await readPageContentWithWorkspaceFallback({
|
||||
userId,
|
||||
storageKey: row.storage_key,
|
||||
sourceSnapshotJson: row.source_snapshot_json,
|
||||
pageType: row.page_type,
|
||||
});
|
||||
let snapshot = {};
|
||||
try {
|
||||
snapshot = parseJsonColumn(row.source_snapshot_json);
|
||||
|
||||
Reference in New Issue
Block a user