101 lines
2.7 KiB
TypeScript
101 lines
2.7 KiB
TypeScript
import { and, eq } from "drizzle-orm";
|
|
|
|
import type { CanvasCapabilityClientCommand } from "@/lib/canvas/capabilities/client-command";
|
|
import { db } from "@/lib/db";
|
|
import { canvasProject } from "@/lib/db/schema";
|
|
|
|
export class CanvasCapabilityRuntimeError extends Error {
|
|
status: number;
|
|
code: string;
|
|
|
|
constructor(message: string, status = 400, code = "CANVAS_CAPABILITY_ERROR") {
|
|
super(message);
|
|
this.name = "CanvasCapabilityRuntimeError";
|
|
this.status = status;
|
|
this.code = code;
|
|
}
|
|
}
|
|
|
|
export type CanvasCapabilityTarget = {
|
|
node: Record<string, any>;
|
|
nodeId: string;
|
|
sourceImageUrl: string;
|
|
assetId?: string;
|
|
title: string;
|
|
};
|
|
|
|
export async function resolveCanvasCapabilityContext(params: {
|
|
command: CanvasCapabilityClientCommand;
|
|
projectId: string;
|
|
requiresRemoteImage?: boolean;
|
|
userId: string;
|
|
}) {
|
|
const [project] = await db
|
|
.select()
|
|
.from(canvasProject)
|
|
.where(
|
|
and(
|
|
eq(canvasProject.id, params.projectId),
|
|
eq(canvasProject.userId, params.userId)
|
|
)
|
|
)
|
|
.limit(1);
|
|
|
|
if (!project) {
|
|
throw new CanvasCapabilityRuntimeError(
|
|
"画布不存在或无权访问",
|
|
404,
|
|
"CANVAS_CAPABILITY_PROJECT_NOT_FOUND"
|
|
);
|
|
}
|
|
|
|
const canvasData =
|
|
project.canvasData && typeof project.canvasData === "object"
|
|
? (project.canvasData as Record<string, any>)
|
|
: {};
|
|
const nodes = Array.isArray(canvasData.nodes) ? canvasData.nodes : [];
|
|
const nodeById = new Map<string, Record<string, any>>(
|
|
nodes.map((node: Record<string, any>) => [String(node?.id || ""), node])
|
|
);
|
|
const targets = params.command.nodeIds.map((nodeId) => {
|
|
const node = nodeById.get(nodeId);
|
|
if (!node) {
|
|
throw new CanvasCapabilityRuntimeError(
|
|
`选中节点不存在:${nodeId}`,
|
|
404,
|
|
"CANVAS_CAPABILITY_NODE_NOT_FOUND"
|
|
);
|
|
}
|
|
if (node.type !== "image") {
|
|
throw new CanvasCapabilityRuntimeError(
|
|
`能力仅支持图片节点:${nodeId}`,
|
|
400,
|
|
"CANVAS_CAPABILITY_INVALID_NODE_TYPE"
|
|
);
|
|
}
|
|
const data =
|
|
node.data && typeof node.data === "object" ? node.data : {};
|
|
const sourceImageUrl = String(data.src || data.url || "").trim();
|
|
if (params.requiresRemoteImage !== false && !/^https?:\/\//i.test(sourceImageUrl)) {
|
|
throw new CanvasCapabilityRuntimeError(
|
|
`图片尚未上传完成:${nodeId}`,
|
|
409,
|
|
"CANVAS_CAPABILITY_IMAGE_NOT_REMOTE"
|
|
);
|
|
}
|
|
return {
|
|
node,
|
|
nodeId,
|
|
sourceImageUrl,
|
|
assetId: String(data.assetId || "").trim() || undefined,
|
|
title: String(data.title || data.prompt || "图片").trim() || "图片",
|
|
} satisfies CanvasCapabilityTarget;
|
|
});
|
|
|
|
return {
|
|
project,
|
|
canvasData,
|
|
targets,
|
|
};
|
|
}
|