fix: stabilize rpg publish and launch

This commit is contained in:
kdletters
2026-05-21 20:20:06 +08:00
parent 224a26d318
commit a9d23a8a44
14 changed files with 614 additions and 82 deletions

View File

@@ -1626,39 +1626,20 @@ pub async fn execute_custom_world_agent_action(
)
})?
} else if action == "publish_world" {
let mut publish_payload = serde_json::to_value(&payload).map_err(|error| {
let publish_payload = serialize_publish_world_action_payload(
resolve_author_public_user_code(&state, &authenticated, &request_context)?,
resolve_author_display_name(&state, &authenticated),
)
.map_err(|error| {
custom_world_error_response(
&request_context,
AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({
"provider": "custom-world-agent",
"message": format!("action payload JSON 序列化失败:{error}"),
"message": error,
})),
)
})?;
if let Some(object) = publish_payload.as_object_mut() {
// 发布到广场时必须写入真实作者公开信息,避免 gallery 投影落成匿名兜底数据。
object.insert(
"authorPublicUserCode".to_string(),
Value::String(resolve_author_public_user_code(
&state,
&authenticated,
&request_context,
)?),
);
object.insert(
"authorDisplayName".to_string(),
Value::String(resolve_author_display_name(&state, &authenticated)),
);
}
serde_json::to_string(&publish_payload).map_err(|error| {
custom_world_error_response(
&request_context,
AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({
"provider": "custom-world-agent",
"message": format!("action payload JSON 序列化失败:{error}"),
})),
)
})?
publish_payload
} else {
serde_json::to_string(&payload).map_err(|error| {
custom_world_error_response(
@@ -1734,6 +1715,23 @@ fn serialize_sync_result_profile_action_payload(
.map_err(|error| format!("action payload JSON 序列化失败:{error}"))
}
fn serialize_publish_world_action_payload(
author_public_user_code: String,
author_display_name: String,
) -> Result<String, String> {
// 中文注释:发布动作只提交动作名和作者公开信息。
// 结果页当前 profile 必须先通过 sync_result_profile 写入 session
// SpacetimeDB 发布时再从 session.draft_profile_json 读取草稿真相,避免前端
// draftProfile / legacyResultProfile / profile 旧载荷覆盖刚保存的内容。
let payload_value = json!({
"action": "publish_world",
"authorPublicUserCode": author_public_user_code,
"authorDisplayName": author_display_name,
});
serde_json::to_string(&payload_value)
.map_err(|error| format!("action payload JSON 序列化失败:{error}"))
}
fn canonicalize_custom_world_library_profile_payload(
mut profile: Value,
) -> Result<(Value, CustomWorldProfileMetadata), String> {
@@ -3414,6 +3412,36 @@ mod tests {
);
}
#[test]
fn publish_world_payload_only_contains_action_and_author_identity() {
let payload_json =
serialize_publish_world_action_payload("TN-0001".to_string(), "潮汐作者".to_string())
.expect("publish payload serializes");
let payload_value: Value =
serde_json::from_str(&payload_json).expect("payload should be valid JSON");
let object = payload_value
.as_object()
.expect("publish payload should be object");
assert_eq!(object.len(), 3);
assert_eq!(
object.get("action").and_then(Value::as_str),
Some("publish_world")
);
assert_eq!(
object.get("authorPublicUserCode").and_then(Value::as_str),
Some("TN-0001")
);
assert_eq!(
object.get("authorDisplayName").and_then(Value::as_str),
Some("潮汐作者")
);
assert!(!object.contains_key("profile"));
assert!(!object.contains_key("draftProfile"));
assert!(!object.contains_key("legacyResultProfile"));
assert!(!object.contains_key("settingText"));
}
#[test]
fn custom_world_library_profile_payload_is_canonicalized_on_server() {
let (profile, metadata) = canonicalize_custom_world_library_profile_payload(json!({