lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit e113eececff4d701076f8a492fa72323679df915
parent 2081f41c953d8c8cdc63e245aa95cbd72e69e5bd
Author: triesap <tyson@radroots.org>
Date:   Tue, 23 Jun 2026 10:40:06 +0000

simplex: expose app store workbench state

- list app-store outbox records through a typed API

- add a disposable runtime-state reset that preserves profiles

- cover reset behavior and outbox listing in app-store tests

Diffstat:
Mcrates/simplex_app_store/src/store.rs | 107++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 106 insertions(+), 1 deletion(-)

diff --git a/crates/simplex_app_store/src/store.rs b/crates/simplex_app_store/src/store.rs @@ -677,6 +677,17 @@ impl RadrootsSimplexAppStore { collect_rows(statement.query_map([], outbox_message_from_row)?) } + pub fn list_outbox_messages( + &self, + ) -> Result<Vec<RadrootsSimplexAppOutboxMessage>, RadrootsSimplexAppStoreError> { + let mut statement = self.connection.prepare( + "SELECT outbox_id, chat_item_id, connection_id, conversation_id, chat_msg_id, body, status, runtime_message_id, retry_after_unix, created_at_unix + FROM outbox_messages + ORDER BY created_at_unix, outbox_id", + )?; + collect_rows(statement.query_map([], outbox_message_from_row)?) + } + pub fn mark_outbox_message_queued( &self, outbox_id: &str, @@ -822,6 +833,21 @@ impl RadrootsSimplexAppStore { )?; collect_rows(statement.query_map([], unsupported_event_from_row)?) } + + pub fn reset_disposable_runtime_state(&self) -> Result<(), RadrootsSimplexAppStoreError> { + let transaction = self.connection.unchecked_transaction()?; + transaction.execute("DELETE FROM unsupported_protocol_events", [])?; + transaction.execute("DELETE FROM inbound_child_events", [])?; + transaction.execute("DELETE FROM inbound_message_log", [])?; + transaction.execute("DELETE FROM outbox_messages", [])?; + transaction.execute("DELETE FROM chat_items", [])?; + transaction.execute("DELETE FROM queue_endpoints", [])?; + transaction.execute("DELETE FROM conversations", [])?; + transaction.execute("DELETE FROM connections", [])?; + transaction.execute("DELETE FROM contacts", [])?; + transaction.commit()?; + Ok(()) + } } fn load_or_create_database_key( @@ -2484,7 +2510,86 @@ mod tests { let page = store.chat_page("conversation-1", 10).expect("page"); assert_eq!(page, vec![draft.chat_item]); let pending = store.pending_outbox_messages().expect("pending"); - assert_eq!(pending, vec![draft.outbox_message]); + assert_eq!(pending, vec![draft.outbox_message.clone()]); + assert_eq!( + store.list_outbox_messages().expect("outbox"), + vec![draft.outbox_message] + ); + } + + #[test] + fn reset_disposable_runtime_state_preserves_profiles_and_clears_messages() { + let temp = tempfile::tempdir().expect("temp"); + let path = temp.path().join("simplex.sqlite"); + let vault = Arc::new(RadrootsSecretVaultMemory::new()); + let store = memory_store(&path, vault).expect("store"); + seed_store(&store); + + let draft = store + .create_outbound_text_with_test_msg_id(&outbound_request(), "AQIDBAUGBwgJCgsM") + .expect("draft"); + let commit = store + .commit_inbound_text(&RadrootsSimplexAppInboundTextRequest { + chat_msg_id: Some("AgIDBAUGBwgJCgsM".into()), + broker_message_id_hash: b"reset-broker-hash".to_vec(), + message_hash: b"reset-message-hash".to_vec(), + runtime_ack_handle: "ack-handle-reset".into(), + ..inbound_text_request() + }) + .expect("inbound"); + store + .record_unsupported_protocol_event(&RadrootsSimplexAppUnsupportedProtocolEvent { + event_id: "unsupported-1".into(), + connection_id: Some("connection-1".into()), + event_kind: "x.future".into(), + payload_json: "{}".into(), + status: "stored".into(), + received_at_unix: 11, + }) + .expect("unsupported"); + + assert_eq!(store.pending_outbox_messages().expect("outbox").len(), 1); + assert_eq!( + store.pending_ack_messages().expect("acks"), + vec![commit.inbound] + ); + assert_eq!( + store + .list_unsupported_protocol_events() + .expect("unsupported") + .len(), + 1 + ); + + store + .reset_disposable_runtime_state() + .expect("reset disposable state"); + + assert_eq!( + store.get_profile("profile-1").expect("profile"), + Some(profile()) + ); + assert!(store.pending_outbox_messages().expect("outbox").is_empty()); + assert!(store.list_outbox_messages().expect("outbox").is_empty()); + assert!(store.pending_ack_messages().expect("acks").is_empty()); + assert!( + store + .chat_page("conversation-1", 10) + .expect("chat") + .is_empty() + ); + assert!( + store + .list_unsupported_protocol_events() + .expect("unsupported") + .is_empty() + ); + assert!( + store + .mark_outbox_message_sent(&draft.outbox_message.outbox_id) + .expect("missing") + .is_none() + ); } #[test]