Bump to v0.6.1 — native file upload, mention names, connection stability

- Native file picker (+) in compose box uploads via Rust backend (reqwest)
- Pasting a local file path auto-uploads instead of inserting text
- @mentions resolve to profile display names via useProfile hook
- Connection indicator uses 15s grace period before showing offline
- Upload uses correct nostr.build v2 API; Rust-side multipart for native picks
- Content parser extracted to src/lib/parsing.ts
This commit is contained in:
Jure
2026-03-18 14:55:29 +01:00
parent ef189932e6
commit fbf05e8f90
16 changed files with 776 additions and 253 deletions

View File

@@ -37,6 +37,51 @@ fn delete_nsec(pubkey: String) -> Result<(), String> {
}
}
// ── File upload ─────────────────────────────────────────────────────────────
#[tauri::command]
async fn upload_file(path: String) -> Result<String, String> {
let file_bytes = std::fs::read(&path).map_err(|e| format!("Failed to read file: {e}"))?;
let file_name = std::path::Path::new(&path)
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("file")
.to_string();
let mime = mime_guess::from_path(&path)
.first_or_octet_stream()
.to_string();
let part = reqwest::multipart::Part::bytes(file_bytes)
.file_name(file_name)
.mime_str(&mime)
.map_err(|e| format!("MIME error: {e}"))?;
let form = reqwest::multipart::Form::new().part("file", part);
let client = reqwest::Client::new();
let resp = client
.post("https://nostr.build/api/v2/upload/files")
.multipart(form)
.send()
.await
.map_err(|e| format!("Upload request failed: {e}"))?;
if !resp.status().is_success() {
return Err(format!("Upload failed (HTTP {})", resp.status()));
}
let data: serde_json::Value = resp
.json()
.await
.map_err(|e| format!("Failed to parse response: {e}"))?;
if data["status"] == "success" {
if let Some(url) = data["data"][0]["url"].as_str() {
return Ok(url.to_string());
}
}
Err(data["message"].as_str().unwrap_or("Upload failed — no URL returned").to_string())
}
// ── SQLite note/profile cache ────────────────────────────────────────────────
struct DbState(Mutex<Connection>);
@@ -142,6 +187,8 @@ pub fn run() {
.plugin(tauri_plugin_updater::Builder::new().build())
.plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_fs::init())
.setup(|app| {
// ── SQLite ───────────────────────────────────────────────────────
let data_dir = app.path().app_data_dir()?;
@@ -203,6 +250,7 @@ pub fn run() {
store_nsec,
load_nsec,
delete_nsec,
upload_file,
db_save_notes,
db_load_feed,
db_save_profile,