20260513 mindmap优化01

This commit is contained in:
lix-2026
2026-05-13 22:43:16 +08:00
parent 17c003976b
commit b4a452a8b7
89 changed files with 11557 additions and 707 deletions
+80 -27
View File
@@ -8,6 +8,7 @@ use bridge_runtime::{
};
use serde_json::{json, Value};
use std::fs;
use std::sync::OnceLock;
use std::time::Duration;
use time::{format_description::well_known::Rfc3339, OffsetDateTime};
@@ -19,6 +20,32 @@ const HEADER_SOURCE_CLIENT: &str = "x-mnote-source-client";
const HEADER_IDEMPOTENCY_KEY: &str = "x-idempotency-key";
const COOKIE_MNOTE_WEB_CONVEX_TOKEN: &str = "mnote_web_convex_token";
const COOKIE_CONVEX_AUTH_JWT: &str = "__convexAuthJWT";
static CONVEX_HTTP_CLIENT: OnceLock<reqwest::Client> = OnceLock::new();
fn convex_http_client(context: &RequestContext) -> Result<&'static reqwest::Client, WebError> {
if let Some(client) = CONVEX_HTTP_CLIENT.get() {
return Ok(client);
}
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(20))
.pool_max_idle_per_host(16)
.pool_idle_timeout(Duration::from_secs(30))
.build()
.map_err(|error| {
WebError::internal(format!("Convex HTTP 客户端创建失败: {error}"))
.with_context(context)
.with_header("x-error-phase", "client_build")
.with_header("x-upstream-service", "convex")
})?;
let _ = CONVEX_HTTP_CLIENT.set(client);
CONVEX_HTTP_CLIENT.get().ok_or_else(|| {
WebError::internal("Convex HTTP 客户端初始化失败")
.with_context(context)
.with_header("x-error-phase", "client_build")
.with_header("x-upstream-service", "convex")
})
}
fn read_env_or_dotenv(key: &str) -> Option<String> {
if let Ok(value) = std::env::var(key) {
@@ -232,15 +259,7 @@ pub async fn execute_convex_query_plan(
"args": plan.args_json,
});
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(20))
.build()
.map_err(|error| {
WebError::internal(format!("Convex HTTP 客户端创建失败: {error}"))
.with_context(context)
.with_header("x-error-phase", "client_build")
.with_header("x-upstream-service", "convex")
})?;
let client = convex_http_client(context)?;
let mut request = client
.post(format!("{}/api/query", convex_url(config, context)?))
@@ -357,6 +376,18 @@ pub async fn execute_convex_query_by_name(
fn convex_command_args_for_plan(plan: &RuntimeCommandExecutionPlan) -> Value {
let mut args = plan.args_json.clone();
if matches!(plan.command_name.as_str(), "mindmaps.put")
|| matches!(plan.function_name.as_str(), "mindmaps:put")
{
if let Value::Object(map) = &mut args {
// Rust plan 保留 tree domain event / stream hint 作为正式契约;
// Convex mindmaps.put legacy validator 仍只接收真实写入字段。
map.remove("streamDeltaHint");
map.remove("domainEventHint");
map.remove("domainEventPlan");
map.remove("domainEventPlans");
}
}
if matches!(
plan.command_name.as_str(),
"documents.save" | "page.body.save"
@@ -414,15 +445,7 @@ pub async fn execute_convex_command_plan(
"args": [convex_command_args_for_plan(plan)],
});
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(20))
.build()
.map_err(|error| {
WebError::internal(format!("Convex HTTP 客户端创建失败: {error}"))
.with_context(context)
.with_header("x-error-phase", "client_build")
.with_header("x-upstream-service", "convex")
})?;
let client = convex_http_client(context)?;
let mut request = client
.post(format!("{}/api/mutation", convex_url(config, context)?))
@@ -550,15 +573,7 @@ pub async fn execute_convex_mutation_by_name(
"args": [args],
});
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(20))
.build()
.map_err(|error| {
WebError::internal(format!("Convex HTTP 客户端创建失败: {error}"))
.with_context(context)
.with_header("x-error-phase", "client_build")
.with_header("x-upstream-service", "convex")
})?;
let client = convex_http_client(context)?;
let mut request = client
.post(format!("{}/api/mutation", convex_url(config, context)?))
@@ -847,6 +862,44 @@ mod tests {
);
}
#[test]
fn convex_command_args_strips_mindmap_put_bridge_artifacts_for_legacy_mutation() {
let plan = RuntimeCommandExecutionPlan {
command_name: "mindmaps.put".into(),
command_id: "cmd_mindmap_put_1".into(),
function_name: "mindmaps:put".into(),
workspace_id: Some("ws_1".into()),
request_id: "req_1".into(),
trace_id: "trace_1".into(),
actor_id: "actor_1".into(),
idempotency_key: None,
source: json!({}),
payload_json: "{}".into(),
args_json: json!({
"docId": "doc_1",
"mindmapId": "mind_1",
"data": {"data": {"text": "KMIND"}, "children": []},
"createOnly": false,
"streamDeltaHint": {"family": "tree"},
"domainEventHint": {"eventType": "tree.resource.mindmap.put"},
"domainEventPlan": {"eventType": "tree.resource.mindmap.put"},
"domainEventPlans": [{"eventType": "tree.resource.mindmap.put"}],
}),
};
let args = convex_command_args_for_plan(&plan);
assert_eq!(
args,
json!({
"docId": "doc_1",
"mindmapId": "mind_1",
"data": {"data": {"text": "KMIND"}, "children": []},
"createOnly": false,
})
);
}
#[test]
fn convex_command_args_adapts_mindmap_command_apply_for_legacy_mutation() {
let plan = RuntimeCommandExecutionPlan {