//! Tauri command surface for the local store — the offline mirror of the REST API //! the frontend's repository seam calls. Each command locks the shared connection and //! delegates to `store`; errors are stringified for the JS boundary. adapters/local.ts //! (M10.5) invokes these. use serde_json::Value; use tauri::State; use thoughtsync_core::local::models::*; use thoughtsync_core::local::retention; use thoughtsync_core::local::store; use thoughtsync_core::local::Db; use thoughtsync_core::sync::state; // A macro would hide the (very regular) locking; kept explicit so each command reads // as an obvious lock -> delegate -> stringify. #[tauri::command] pub fn config_get(db: State<'_, Db>) -> PublicConfig { // What the Trash view counts down against: the linked server's window if we know // it, else this device's own. Reading it here rather than hard-coding the offline // default is what keeps the deadline on screen equal to the one that will actually // be enforced. A store error falls back to the default rather than failing the // call — the app must still boot. let fallback = retention::LOCAL_RETENTION_DAYS; let retention_days = match db.0.lock() { Ok(conn) => state::effective_retention_days(&conn, fallback).unwrap_or(fallback), Err(_) => fallback, }; // Offline defaults: no signups, no server-side URL unfurling (needs network). PublicConfig { site_name: "ThoughtSync".to_string(), allow_registration: false, version: env!("CARGO_PKG_VERSION").to_string(), enable_url_unfurl: false, trash_retention_days: retention_days.max(0) as u32, } } #[tauri::command] pub fn auth_me() -> User { // The single synthetic local user, so the auth-gated router resolves with no login. User { id: "local".to_string(), email: "local@thoughtsync.app".to_string(), display_name: "You".to_string(), email_verified: true, is_admin: false, } } #[tauri::command] pub fn notes_list(query: ListQuery, db: State<'_, Db>) -> Result, String> { let conn = db.0.lock().map_err(|e| e.to_string())?; store::list_notes(&conn, &query).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_get(id: String, db: State<'_, Db>) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::get_note(&conn, &id).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_create(input: NoteCreateInput, db: State<'_, Db>) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::create_note(&conn, &input).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_update(id: String, changes: Value, db: State<'_, Db>) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::update_note(&conn, &id, &changes).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_complete_reminder(id: String, db: State<'_, Db>) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::complete_reminder(&conn, &id).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_snooze_reminder(id: String, minutes: i64, db: State<'_, Db>) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::snooze_reminder(&conn, &id, minutes).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_set_labels( id: String, label_ids: Vec, db: State<'_, Db>, ) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::set_labels(&conn, &id, &label_ids).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_add_item(id: String, text: String, db: State<'_, Db>) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::add_item(&conn, &id, &text).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_update_item( id: String, item_id: String, changes: Value, db: State<'_, Db>, ) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::update_item(&conn, &id, &item_id, &changes).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_delete_item(id: String, item_id: String, db: State<'_, Db>) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::delete_item(&conn, &id, &item_id).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_delete_attachment( id: String, att_id: String, db: State<'_, Db>, ) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::delete_attachment(&conn, &id, &att_id).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_delete_preview( id: String, preview_id: String, db: State<'_, Db>, ) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::delete_preview(&conn, &id, &preview_id).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_reorder(ordered_ids: Vec, db: State<'_, Db>) -> Result<(), String> { let conn = db.0.lock().map_err(|e| e.to_string())?; store::reorder(&conn, &ordered_ids).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_trash(id: String, db: State<'_, Db>) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::trash(&conn, &id).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_restore(id: String, db: State<'_, Db>) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::restore(&conn, &id).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_delete_forever(id: String, db: State<'_, Db>) -> Result<(), String> { let conn = db.0.lock().map_err(|e| e.to_string())?; store::delete_forever(&conn, &id).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_revisions(id: String, db: State<'_, Db>) -> Result, String> { let conn = db.0.lock().map_err(|e| e.to_string())?; store::revisions(&conn, &id).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_restore_revision( id: String, rev_id: String, db: State<'_, Db>, ) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::restore_revision(&conn, &id, &rev_id).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_reminders(db: State<'_, Db>) -> Result, String> { let conn = db.0.lock().map_err(|e| e.to_string())?; store::reminders(&conn).map_err(|e| e.to_string()) } #[tauri::command] pub fn notes_titles(db: State<'_, Db>) -> Result, String> { let conn = db.0.lock().map_err(|e| e.to_string())?; store::titles(&conn).map_err(|e| e.to_string()) } #[tauri::command] pub fn labels_list(db: State<'_, Db>) -> Result, String> { let conn = db.0.lock().map_err(|e| e.to_string())?; store::list_labels(&conn).map_err(|e| e.to_string()) } #[tauri::command] pub fn labels_create(name: String, db: State<'_, Db>) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::create_label(&conn, &name).map_err(|e| e.to_string()) } #[tauri::command] pub fn labels_rename(id: String, name: String, db: State<'_, Db>) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::rename_label(&conn, &id, &name).map_err(|e| e.to_string()) } #[tauri::command] pub fn labels_set_color(id: String, color: String, db: State<'_, Db>) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::set_label_color(&conn, &id, &color).map_err(|e| e.to_string()) } #[tauri::command] pub fn labels_remove(id: String, db: State<'_, Db>) -> Result<(), String> { let conn = db.0.lock().map_err(|e| e.to_string())?; store::remove_label(&conn, &id).map_err(|e| e.to_string()) } #[tauri::command] pub fn labels_merge(source_id: String, into: String, db: State<'_, Db>) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::merge_labels(&conn, &source_id, &into).map_err(|e| e.to_string()) } #[tauri::command] pub fn saved_filters_list(db: State<'_, Db>) -> Result, String> { let conn = db.0.lock().map_err(|e| e.to_string())?; store::list_saved_filters(&conn).map_err(|e| e.to_string()) } #[tauri::command] pub fn saved_filters_create( name: String, params: Value, db: State<'_, Db>, ) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::create_saved_filter(&conn, &name, ¶ms).map_err(|e| e.to_string()) } #[tauri::command] pub fn saved_filters_remove(id: String, db: State<'_, Db>) -> Result<(), String> { let conn = db.0.lock().map_err(|e| e.to_string())?; store::remove_saved_filter(&conn, &id).map_err(|e| e.to_string()) } #[tauri::command] pub fn saved_filters_rename( id: String, name: String, db: State<'_, Db>, ) -> Result { let conn = db.0.lock().map_err(|e| e.to_string())?; store::rename_saved_filter(&conn, &id, &name).map_err(|e| e.to_string()) }