feat: consolidate local-first mnote web runtime
This commit is contained in:
@@ -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"] }
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user