chore(release): 版本发布 - 发布 v1.2.8.rc3 候选版本

修复生产前端 Rolldown 分包循环依赖白屏,补齐画布引用排序与素材 payload 合同,并同步工作流生成素材字段。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
ddCat
2026-09-10 13:48:31 +08:00
parent 01084c9a0f
commit 916043fb5a
21 changed files with 535 additions and 37 deletions

View File

@@ -1,6 +1,7 @@
import { useEffect, useMemo, useState } from "react";
import type { CanvasResourceReference } from "@/lib/canvas/canvas-resource-references";
import { loadCanvasDrawingPreview } from "@/lib/canvas/canvas-drawing-storage";
import { resolveImageUrl } from "@/services/image-storage";
type ResolvedPreview = {
@@ -10,13 +11,14 @@ type ResolvedPreview = {
const previewPromiseCache = new Map<string, Promise<string>>();
export function useResolvedCanvasResourceReferences(references: CanvasResourceReference[]) {
export function useResolvedCanvasResourceReferences(references: CanvasResourceReference[], options?: { projectId?: string }) {
const projectId = options?.projectId;
const requests = useMemo(
() => references.flatMap((reference) => {
const identity = previewIdentity(reference);
const identity = previewIdentity(reference, projectId);
return identity ? [{ reference, identity }] : [];
}),
[references],
[projectId, references],
);
const [resolvedById, setResolvedById] = useState<Record<string, ResolvedPreview>>({});
@@ -27,7 +29,7 @@ export function useResolvedCanvasResourceReferences(references: CanvasResourceRe
requests.map(async ({ reference, identity }) => ({
id: reference.id,
identity,
url: await resolveReferencePreview(reference, identity),
url: await resolveReferencePreview(reference, identity, projectId),
})),
).then((resolved) => {
if (cancelled) return;
@@ -45,27 +47,39 @@ export function useResolvedCanvasResourceReferences(references: CanvasResourceRe
return () => {
cancelled = true;
};
}, [requests]);
}, [projectId, requests]);
return useMemo(
() => references.map((reference) => {
const identity = previewIdentity(reference);
const identity = previewIdentity(reference, projectId);
const resolved = identity ? resolvedById[reference.id] : undefined;
return resolved?.identity === identity && resolved.url !== reference.previewUrl ? { ...reference, previewUrl: resolved.url } : reference;
}),
[references, resolvedById],
[projectId, references, resolvedById],
);
}
function previewIdentity(reference: CanvasResourceReference) {
function previewIdentity(reference: CanvasResourceReference, projectId?: string) {
if (reference.drawingId && projectId) return `drawing:${projectId}:${reference.drawingId}:${reference.drawingRevision || 0}`;
const storageKey = reference.kind === "video" ? reference.previewStorageKey : reference.storageKey;
if (!storageKey || !["image", "video", "character"].includes(reference.kind)) return "";
return `${reference.kind}:${storageKey}`;
}
function resolveReferencePreview(reference: CanvasResourceReference, identity: string) {
function resolveReferencePreview(reference: CanvasResourceReference, identity: string, projectId?: string) {
const cached = previewPromiseCache.get(identity);
if (cached) return cached;
if (reference.drawingId && projectId) {
const pending = loadCanvasDrawingPreview(projectId, reference.drawingId)
.then((preview) => preview ? blobToDataUrl(preview) : reference.previewUrl || "")
.catch(() => reference.previewUrl || "")
.then((url) => {
if (!url) previewPromiseCache.delete(identity);
return url;
});
previewPromiseCache.set(identity, pending);
return pending;
}
const storageKey = reference.kind === "video" ? reference.previewStorageKey : reference.storageKey;
const pending = resolveImageUrl(storageKey, reference.previewUrl || "", { cacheMiss: true })
.catch(() => reference.previewUrl || "")
@@ -76,3 +90,12 @@ function resolveReferencePreview(reference: CanvasResourceReference, identity: s
previewPromiseCache.set(identity, pending);
return pending;
}
function blobToDataUrl(blob: Blob) {
return new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.onerror = () => reject(reader.error || new Error("读取绘图预览失败"));
reader.onload = () => resolve(typeof reader.result === "string" ? reader.result : "");
reader.readAsDataURL(blob);
});
}