release: prepare OpenNexus 0.5.2-alpha1

This commit is contained in:
OpenNexus Release Bot
2026-09-18 20:41:21 +08:00
parent 32bc2ddccb
commit 5c3cb8003c
51 changed files with 590 additions and 9327 deletions
+1 -1
View File
@@ -3242,7 +3242,7 @@ dependencies = [
[[package]]
name = "notesagent-desktop"
version = "0.5.1-alpha"
version = "0.5.2-alpha1"
dependencies = [
"argon2",
"base64 0.22.1",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "notesagent-desktop"
version = "0.5.1-alpha"
version = "0.5.2-alpha1"
edition = "2021"
rust-version = "1.89"
+1
View File
@@ -50,6 +50,7 @@ fn main() {
"core_request",
"core_request_prepare",
"core_request_cancel",
"export_save",
"core_stream",
"core_stream_cancel",
"editor_capabilities",
@@ -18,6 +18,7 @@
"allow-core-request",
"allow-core-request-prepare",
"allow-core-request-cancel",
"allow-export-save",
"allow-core-stream",
"allow-core-stream-cancel",
"allow-workspace-choose",
@@ -0,0 +1,11 @@
# Automatically generated - DO NOT EDIT!
[[permission]]
identifier = "allow-export-save"
description = "Enables the export_save command without any pre-configured scope."
commands.allow = ["export_save"]
[[permission]]
identifier = "deny-export-save"
description = "Denies the export_save command without any pre-configured scope."
commands.deny = ["export_save"]
+5
View File
@@ -340,6 +340,11 @@ impl CoreSupervisor {
"HOME",
"USERPROFILE",
"LOCALAPPDATA",
// PDF 浏览器渲染需要从系统安装目录定位 Edge/Chrome;这里只传
// 目录根,不放宽 PATH,也不携带任何凭据或用户配置。
"PROGRAMFILES",
"PROGRAMFILES(X86)",
"ProgramW6432",
] {
if let Some(value) = std::env::var_os(key) {
command.env(key, value);
+87
View File
@@ -461,6 +461,92 @@ async fn core_request(request: CoreRequest, host: State<'_, Host>) -> Result<Cor
.await
}
fn valid_export_job_id(value: &str) -> bool {
value.len() == 19
&& value.starts_with("export_")
&& value[7..].bytes().all(|byte| byte.is_ascii_hexdigit())
}
fn export_file_name(value: &str) -> Result<(&str, &'static str), String> {
if value.len() > 120 || Path::new(value).file_name().and_then(|name| name.to_str()) != Some(value)
{
return Err("EXPORT_FILE_NAME_INVALID".into());
}
let extension = Path::new(value)
.extension()
.and_then(|extension| extension.to_str())
.map(str::to_ascii_lowercase)
.ok_or("EXPORT_FILE_NAME_INVALID")?;
let label = match extension.as_str() {
"pdf" => "PDF",
"docx" => "Word document",
"html" => "HTML",
_ => return Err("EXPORT_FILE_NAME_INVALID".into()),
};
Ok((value, label))
}
/// 由原生保存对话框选择目标,再从已认证的本机 Core 直接写入产物。
/// 文件内容不绕回 WebView,避免大文件重复 Base64 编解码。
#[tauri::command]
async fn export_save(
job_id: String,
file_name: String,
host: State<'_, Host>,
) -> Result<Option<String>, String> {
if !valid_export_job_id(&job_id) {
return Err("EXPORT_JOB_ID_INVALID".into());
}
let (file_name, label) = export_file_name(&file_name)?;
let extension = Path::new(file_name)
.extension()
.and_then(|value| value.to_str())
.ok_or("EXPORT_FILE_NAME_INVALID")?;
let Some(path) = rfd::FileDialog::new()
.set_title("保存导出文件")
.set_file_name(file_name)
.add_filter(label, &[extension])
.save_file()
else {
return Ok(None);
};
let core = host.core.clone();
let core_path = format!("/api/exports/{job_id}/file");
let session = tauri::async_runtime::spawn_blocking(move || {
core.lock()
.map_err(|_| "HOST_BUSY")?
.as_mut()
.ok_or("CORE_UNAVAILABLE")?
.request_session(&core_path)
})
.await
.map_err(|_| "CORE_UNAVAILABLE")??;
let response = reqwest::Client::builder()
.timeout(Duration::from_secs(120))
.redirect(reqwest::redirect::Policy::none())
.no_proxy()
.build()
.map_err(|_| "CORE_CLIENT_ERROR")?
.get(&session.url)
.header(reqwest::header::AUTHORIZATION, session.authorization.as_str())
.header("X-Core-Generation", &session.generation)
.send()
.await
.map_err(|_| "CORE_UNAVAILABLE")?;
if !response.status().is_success() {
return Err("EXPORT_DOWNLOAD_FAILED".into());
}
let bytes = read_core_response(response).await?;
let saved = path.to_string_lossy().into_owned();
tauri::async_runtime::spawn_blocking(move || {
std::fs::write(path, bytes).map_err(|_| "EXPORT_SAVE_FAILED")
})
.await
.map_err(|_| "EXPORT_SAVE_FAILED")??;
Ok(Some(saved))
}
#[tauri::command]
fn core_stream_cancel(host: State<'_, Host>, request_id: String) -> Result<(), String> {
if let Some(task) = host
@@ -1131,6 +1217,7 @@ fn main() {
core_request,
core_request_prepare,
core_request_cancel,
export_save,
core_stream,
core_stream_cancel,
editor_capabilities,
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "OpenNexus",
"version": "0.5.1-alpha",
"version": "0.5.2-alpha1",
"identifier": "cc.kronecker.notesagent",
"build": {
"beforeDevCommand": "pnpm dev",