fix: include canvas revisions in service saves
This commit is contained in:
parent
733d6338c2
commit
4d65ba0b79
40
lib/canvas/canvas-save-request.ts
Normal file
40
lib/canvas/canvas-save-request.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import type { CanvasState, CanvasWorkspaceType } from "@/types/canvas";
|
||||
|
||||
export type CanvasSaveRevisionOptions = {
|
||||
baseCanvasRevision?: string | null;
|
||||
baseCanvasUpdatedAt?: string | null;
|
||||
};
|
||||
|
||||
function normalizeRevisionValue(value: unknown) {
|
||||
return String(value || "").trim() || undefined;
|
||||
}
|
||||
|
||||
export function mergeCanvasSaveRevisionOptions(params: {
|
||||
options?: CanvasSaveRevisionOptions;
|
||||
fallbackOptions?: CanvasSaveRevisionOptions;
|
||||
}): CanvasSaveRevisionOptions {
|
||||
return {
|
||||
baseCanvasRevision:
|
||||
normalizeRevisionValue(params.options?.baseCanvasRevision) ??
|
||||
normalizeRevisionValue(params.fallbackOptions?.baseCanvasRevision),
|
||||
baseCanvasUpdatedAt:
|
||||
normalizeRevisionValue(params.options?.baseCanvasUpdatedAt) ??
|
||||
normalizeRevisionValue(params.fallbackOptions?.baseCanvasUpdatedAt),
|
||||
};
|
||||
}
|
||||
|
||||
export function buildCanvasSaveRequestBody(params: {
|
||||
canvasData: CanvasState;
|
||||
workspaceType?: CanvasWorkspaceType;
|
||||
options?: CanvasSaveRevisionOptions;
|
||||
fallbackOptions?: CanvasSaveRevisionOptions;
|
||||
}) {
|
||||
const revisionOptions = mergeCanvasSaveRevisionOptions({
|
||||
options: params.options,
|
||||
fallbackOptions: params.fallbackOptions,
|
||||
});
|
||||
|
||||
return params.workspaceType
|
||||
? { canvasData: params.canvasData, workspaceType: params.workspaceType, ...revisionOptions }
|
||||
: { canvasData: params.canvasData, ...revisionOptions };
|
||||
}
|
||||
@ -9,12 +9,17 @@ import type {
|
||||
import type { VideoGenerationMode, VideoRatio, VideoResolution } from '@/types/ai';
|
||||
import { fetchUploadWithRetry } from '@/lib/client/upload-with-retry';
|
||||
import { requestLongTaskResult } from '@/lib/client/long-task';
|
||||
import {
|
||||
buildCanvasSaveRequestBody,
|
||||
type CanvasSaveRevisionOptions,
|
||||
} from '@/lib/canvas/canvas-save-request';
|
||||
import type {
|
||||
EnhanceProKreaModel,
|
||||
EnhanceProOutputFormat,
|
||||
EnhanceProSubjectDetection,
|
||||
} from '@/lib/enhance-pro/config';
|
||||
import { createLogger } from '@/lib/observability/logger';
|
||||
import { useCanvasStore } from '@/store/canvas';
|
||||
|
||||
const log = createLogger("Canvas");
|
||||
|
||||
@ -27,6 +32,15 @@ function logCatch(
|
||||
log.error(`${context} failed`, error, extra);
|
||||
}
|
||||
|
||||
function getCanvasSaveRevisionFallback(): CanvasSaveRevisionOptions {
|
||||
if (typeof window === "undefined") return {};
|
||||
const { canvasRevision, canvasUpdatedAt } = useCanvasStore.getState();
|
||||
return {
|
||||
baseCanvasRevision: canvasRevision,
|
||||
baseCanvasUpdatedAt: canvasUpdatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
// API 响应类型
|
||||
interface ApiResponse<T = any> {
|
||||
success: boolean;
|
||||
@ -196,16 +210,16 @@ export const canvasService = {
|
||||
id: string,
|
||||
canvasData: CanvasState,
|
||||
workspaceType?: CanvasWorkspaceType,
|
||||
options?: {
|
||||
baseCanvasRevision?: string | null;
|
||||
baseCanvasUpdatedAt?: string | null;
|
||||
}
|
||||
options?: CanvasSaveRevisionOptions
|
||||
): Promise<ApiResponse> {
|
||||
try {
|
||||
const requestBody = JSON.stringify(
|
||||
workspaceType
|
||||
? { canvasData, workspaceType, ...options }
|
||||
: { canvasData, ...options }
|
||||
buildCanvasSaveRequestBody({
|
||||
canvasData,
|
||||
workspaceType,
|
||||
options,
|
||||
fallbackOptions: getCanvasSaveRevisionFallback(),
|
||||
})
|
||||
);
|
||||
const doSave = async () =>
|
||||
fetch(`/api/canvas/${id}`, {
|
||||
|
||||
@ -110,6 +110,10 @@ import {
|
||||
isStaleCanvasSaveBaseRevision,
|
||||
parseCanvasRevisionDate,
|
||||
} from "@/lib/canvas/canvas-save-conflict";
|
||||
import {
|
||||
buildCanvasSaveRequestBody,
|
||||
mergeCanvasSaveRevisionOptions,
|
||||
} from "@/lib/canvas/canvas-save-request";
|
||||
import {
|
||||
applyCanvasOperationPlanToCanvasData,
|
||||
CanvasAgentMutationError,
|
||||
@ -257,6 +261,57 @@ test.describe("canvas chat pure helpers", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("builds canvas save requests with fallback revision guards", () => {
|
||||
const canvasData = {
|
||||
nodes: [],
|
||||
edges: [],
|
||||
selectedNodeIds: [],
|
||||
viewport: { x: 0, y: 0, zoom: 1 },
|
||||
tool: "select" as const,
|
||||
};
|
||||
|
||||
expect(
|
||||
mergeCanvasSaveRevisionOptions({
|
||||
fallbackOptions: {
|
||||
baseCanvasRevision: "2026-06-22T00:00:00.000Z",
|
||||
baseCanvasUpdatedAt: "2026-06-22T00:00:00.000Z",
|
||||
},
|
||||
})
|
||||
).toEqual({
|
||||
baseCanvasRevision: "2026-06-22T00:00:00.000Z",
|
||||
baseCanvasUpdatedAt: "2026-06-22T00:00:00.000Z",
|
||||
});
|
||||
expect(
|
||||
mergeCanvasSaveRevisionOptions({
|
||||
options: {
|
||||
baseCanvasRevision: "2026-06-22T00:00:02.000Z",
|
||||
},
|
||||
fallbackOptions: {
|
||||
baseCanvasRevision: "2026-06-22T00:00:00.000Z",
|
||||
baseCanvasUpdatedAt: "2026-06-22T00:00:00.000Z",
|
||||
},
|
||||
})
|
||||
).toEqual({
|
||||
baseCanvasRevision: "2026-06-22T00:00:02.000Z",
|
||||
baseCanvasUpdatedAt: "2026-06-22T00:00:00.000Z",
|
||||
});
|
||||
expect(
|
||||
buildCanvasSaveRequestBody({
|
||||
canvasData,
|
||||
workspaceType: "video",
|
||||
fallbackOptions: {
|
||||
baseCanvasRevision: "2026-06-22T00:00:00.000Z",
|
||||
baseCanvasUpdatedAt: "2026-06-22T00:00:00.000Z",
|
||||
},
|
||||
})
|
||||
).toMatchObject({
|
||||
canvasData,
|
||||
workspaceType: "video",
|
||||
baseCanvasRevision: "2026-06-22T00:00:00.000Z",
|
||||
baseCanvasUpdatedAt: "2026-06-22T00:00:00.000Z",
|
||||
});
|
||||
});
|
||||
|
||||
const plannerContext: CanvasAgentContext = {
|
||||
version: 1,
|
||||
source: "canvas",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user