feat: consolidate local-first mnote web runtime

This commit is contained in:
lix-2026
2026-05-28 22:01:44 +08:00
parent 7354807ee9
commit 39b9a0183a
154 changed files with 13591 additions and 12728 deletions
-1
View File
@@ -11,7 +11,6 @@ core-domain = { path = "../core-domain" }
core-protocol = { path = "../core-protocol" }
event-log = { path = "../event-log" }
index-fts = { path = "../index-fts" }
storage-convex-bridge = { path = "../storage-convex-bridge" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
reqwest = { version = "0.12", default-features = false, features = ["blocking", "json", "rustls-tls"] }
+164 -9
View File
@@ -44,13 +44,168 @@ use serde_json::{json, Value};
use std::collections::{BTreeMap, HashMap, VecDeque};
use std::env;
use std::sync::atomic::{AtomicU64, Ordering};
use storage_convex_bridge::{
build_query_request, build_write_request, BridgeContext, BridgeError, BridgeErrorKind,
};
static TOOL_BLOCK_COUNTER: AtomicU64 = AtomicU64::new(1);
static MINDMAP_UID_COUNTER: AtomicU64 = AtomicU64::new(1);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BridgeContext {
pub deployment_id: Option<String>,
pub project_id: Option<String>,
pub request_id: String,
pub trace_id: String,
pub actor_type: String,
pub actor_id: String,
pub session_id: Option<String>,
pub workspace_id: Option<String>,
pub tenant_id: Option<String>,
pub auth_token: Option<String>,
pub source_channel: String,
pub source_client: String,
pub idempotency_key: Option<String>,
pub validate_only: bool,
pub dry_run: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BridgeErrorKind {
Validation,
Unauthorized,
Conflict,
NotFound,
Transport,
Rejected,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BridgeError {
pub kind: BridgeErrorKind,
pub message: String,
}
pub type BridgeResult<T> = Result<T, BridgeError>;
impl BridgeError {
pub fn validation(message: impl Into<String>) -> Self {
Self {
kind: BridgeErrorKind::Validation,
message: message.into(),
}
}
pub fn transport(message: impl Into<String>) -> Self {
Self {
kind: BridgeErrorKind::Transport,
message: message.into(),
}
}
pub fn not_found(message: impl Into<String>) -> Self {
Self {
kind: BridgeErrorKind::NotFound,
message: message.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RetiredMutationRequest {
pub function_name: String,
pub deployment_id: Option<String>,
pub project_id: Option<String>,
pub workspace_id: Option<String>,
pub request_id: String,
pub trace_id: String,
pub idempotency_key: Option<String>,
pub actor_id: String,
pub payload_json: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RetiredQueryRequest {
pub function_name: String,
pub deployment_id: Option<String>,
pub project_id: Option<String>,
pub workspace_id: Option<String>,
pub request_id: String,
pub trace_id: String,
pub actor_id: String,
pub payload_json: String,
}
fn retired_bridge_error() -> BridgeError {
BridgeError::validation(
"旧 Convex 兼容桥已退役;请改用 local-first Rust/SQLite control-plane 路径",
)
}
pub fn build_query_request<T>(
context: &BridgeContext,
query: &QueryEnvelope<T>,
) -> BridgeResult<RetiredQueryRequest> {
let function_name = legacy_query_function_name(&query.name)?;
Ok(RetiredQueryRequest {
function_name: function_name.to_string(),
deployment_id: context.deployment_id.clone(),
project_id: context.project_id.clone(),
workspace_id: context.workspace_id.clone(),
request_id: context.request_id.clone(),
trace_id: context.trace_id.clone(),
actor_id: context.actor_id.clone(),
payload_json: json!({ "name": query.name }).to_string(),
})
}
pub fn build_write_request<T>(
context: &BridgeContext,
command: &CommandEnvelope<T>,
) -> BridgeResult<RetiredMutationRequest> {
let function_name = legacy_command_function_name(&command.name)?;
Ok(RetiredMutationRequest {
function_name: function_name.to_string(),
deployment_id: context.deployment_id.clone(),
project_id: context.project_id.clone(),
workspace_id: context.workspace_id.clone(),
request_id: context.request_id.clone(),
trace_id: context.trace_id.clone(),
idempotency_key: context.idempotency_key.clone(),
actor_id: context.actor_id.clone(),
payload_json: json!({
"name": command.name,
"commandId": command.command_id,
})
.to_string(),
})
}
fn legacy_query_function_name(name: &str) -> BridgeResult<&'static str> {
match name {
"documents.content.get" => Ok("documents:getContent"),
"documents.meta.get" => Ok("documents:getMeta"),
"mindmaps.get" => Ok("mindmaps:get"),
"search.documents" => Ok("documents:listSearchDataByWorkspace"),
"search_blocks" => Ok("documents:searchBlocks"),
"sidebar.dataset.list" => Ok("sidebar:datasetList"),
_ => Err(retired_bridge_error()),
}
}
fn legacy_command_function_name(name: &str) -> BridgeResult<&'static str> {
match name {
"documents.title.update" => Ok("documents:updateTitle"),
"documents.save" => Ok("documents:updateContent"),
"documents.create" => Ok("documents:createWithParentReference"),
"documents.move" => Ok("documents:move"),
"documents.delete" => Ok("documents:softDelete"),
"documents.restore" => Ok("documents:restore"),
"insert_block" | "blocks.patch" | "blocks.move" | "blocks.embed" => {
Ok("documents:updateContent")
}
"mindmaps.put" => Ok("mindmaps:put"),
_ => Err(retired_bridge_error()),
}
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase", tag = "kind")]
pub enum RuntimeInput {
@@ -1573,7 +1728,7 @@ fn normalize_resource_asset_type(raw: Option<&str>) -> String {
"video" => "video".into(),
"audio" => "audio".into(),
"mindmap" => "mindmap".into(),
"luckysheet" => "luckysheet".into(),
"table" => "table".into(),
_ => "file".into(),
}
}
@@ -1633,7 +1788,7 @@ fn normalize_resource_lifecycle_kind(payload: &ResourceLifecycleCommandPayload)
.map(str::trim)
.unwrap_or("file")
{
"table" | "online-table" | "luckysheet" => "table".into(),
"table" | "online-table" => "table".into(),
"mindmap" | "map" => "mindmap".into(),
_ => "file".into(),
}
@@ -7991,7 +8146,7 @@ fn classify_asset_kind(
if lowered_type == "mindmap" {
return KernelProjectionAssetKind::Mindmap;
}
if lowered_type == "luckysheet" {
if lowered_type == "table" {
return KernelProjectionAssetKind::Table;
}
if is_pdf_asset(file_name, mime_type) {
@@ -19981,10 +20136,10 @@ mod tests {
"id": "table_1",
"workspace_id": "ws_1",
"document_id": "page_root",
"asset_type": "luckysheet",
"file_name": "budget.luckysheet",
"asset_type": "table",
"file_name": "budget.table",
"mime_type": "application/json",
"storage_path": "budget.luckysheet"
"storage_path": "budget.table"
}
],
"mindmap_asset_children": {
+1 -2
View File
@@ -3,9 +3,8 @@ use std::io::{self, Read};
use bridge_runtime::{
build_artifact_success_response, build_failure_response, build_success_response,
execute_runtime_command_artifact, execute_runtime_input, execute_runtime_query,
runtime_input_requests_result, RuntimeFailure, RuntimeInput,
runtime_input_requests_result, BridgeError, BridgeErrorKind, RuntimeFailure, RuntimeInput,
};
use storage_convex_bridge::{BridgeError, BridgeErrorKind};
fn main() {
let input = match read_stdin() {