diff --git a/server-rs/crates/spacetime-module/src/editor_project_storage.rs b/server-rs/crates/spacetime-module/src/editor_project_storage.rs index 70d8f8d52..b356b874c 100644 --- a/server-rs/crates/spacetime-module/src/editor_project_storage.rs +++ b/server-rs/crates/spacetime-module/src/editor_project_storage.rs @@ -1549,6 +1549,7 @@ fn persist_editor_project_layout( input_layers_json, now, )?; + let layers_json = normalize_layout_json(layers_json)?; ctx.db.editor_canvas().canvas_id().delete(&canvas.canvas_id); ctx.db.editor_canvas().insert(EditorCanvas { @@ -5021,6 +5022,50 @@ mod tests { assert_eq!(error, "图片画布图层布局过大"); } + #[test] + fn editor_layout_rejects_merged_result_over_two_mib() { + let incoming = json!([{ + "itemType": "generation-dialog", + "layerId": "generation-dialog:dialog-1", + "resourceId": "generation-dialog:dialog-1", + "padding": "x".repeat(EDITOR_PROJECT_MAX_LAYOUT_JSON_BYTES - 200), + "dialog": { + "id": "dialog-1", + "mode": "generate", + "status": "generating" + } + }]); + let current = json!([ + { + "layerId": "layer-generated", + "resourceId": "resource-generated", + "title": "生成结果" + }, + { + "itemType": "generation-dialog", + "layerId": "generation-dialog:dialog-1", + "resourceId": "generation-dialog:dialog-1", + "dialog": { + "id": "dialog-1", + "mode": "generate", + "status": "idle", + "generatedLayerId": "layer-generated" + } + } + ]); + let merged = merge_completed_canvas_generation_items( + current.to_string().as_str(), + incoming.to_string(), + ) + .expect("merge itself should succeed"); + + assert!(merged.len() > EDITOR_PROJECT_MAX_LAYOUT_JSON_BYTES); + assert_eq!( + normalize_layout_json(merged).expect_err("final merged layout should fail"), + "图片画布图层布局过大" + ); + } + fn public_showcase_asset() -> EditorShowcaseAsset { let now = Timestamp::from_micros_since_unix_epoch(1_000_000); EditorShowcaseAsset {