commit e686fed05fd696eb0b41a945bb86c6f48b41ac9f
parent 7f92d1e26548d0d1c400c4bfae7480a2d451ba1a
Author: triesap <tyson@radroots.org>
Date: Mon, 27 Jul 2026 02:37:21 +0000
outbox: isolate storage feature profiles
- make runtime Tokio imply SQLite support
- gate SQLite APIs behind the SQLite feature
- isolate event-store integration behind an adapter
- verify bare, SQLite, adapter, and full profiles
Diffstat:
4 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/crates/outbox/Cargo.toml b/crates/outbox/Cargo.toml
@@ -12,19 +12,22 @@ homepage.workspace = true
readme = "README"
[features]
-default = ["sqlite", "runtime-tokio"]
+default = ["event-store-adapter"]
sqlite = ["dep:sqlx", "sqlx/sqlite-bundled"]
-runtime-tokio = ["sqlx/runtime-tokio"]
+runtime-tokio = ["sqlite", "sqlx/runtime-tokio"]
+event-store-adapter = [
+ "runtime-tokio",
+ "dep:radroots_event_store",
+ "radroots_event_store/sqlite",
+ "radroots_event_store/runtime-tokio",
+]
[dependencies]
radroots_event = { workspace = true, default-features = false, features = [
"std",
"serde",
] }
-radroots_event_store = { workspace = true, default-features = false, features = [
- "sqlite",
- "runtime-tokio",
-] }
+radroots_event_store = { workspace = true, default-features = false, optional = true }
radroots_transport = { workspace = true, default-features = false }
hex = { workspace = true }
serde = { workspace = true, features = ["std"] }
diff --git a/crates/outbox/src/error.rs b/crates/outbox/src/error.rs
@@ -5,12 +5,14 @@ use thiserror::Error;
#[derive(Debug, Error)]
pub enum RadrootsOutboxError {
+ #[cfg(feature = "sqlite")]
#[error("SQLx error: {0}")]
Sqlx(#[from] sqlx::Error),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
+ #[cfg(feature = "event-store-adapter")]
#[error("Event store error: {0}")]
EventStore(#[from] radroots_event_store::RadrootsEventStoreError),
diff --git a/crates/outbox/src/lib.rs b/crates/outbox/src/lib.rs
@@ -2,11 +2,14 @@
#![forbid(unsafe_code)]
mod error;
+#[cfg(feature = "sqlite")]
mod migrations;
mod model;
+#[cfg(feature = "sqlite")]
mod store;
pub use error::RadrootsOutboxError;
+#[cfg(feature = "sqlite")]
pub use migrations::{OUTBOX_MIGRATION_DOWN, OUTBOX_MIGRATION_UP};
pub use model::{
RadrootsOutboxClaimedEvent, RadrootsOutboxDeliveryAttemptRecord,
@@ -20,4 +23,5 @@ pub use model::{
RadrootsOutboxSignedTradeMutationInput, RadrootsOutboxStatusSummary,
RadrootsOutboxTradeMutationInput,
};
+#[cfg(feature = "sqlite")]
pub use store::RadrootsOutbox;
diff --git a/crates/outbox/src/store.rs b/crates/outbox/src/store.rs
@@ -2,17 +2,18 @@
use crate::RadrootsOutboxError;
use crate::migrations::{OUTBOX_MIGRATION_DOWN, OUTBOX_MIGRATION_UP};
+#[cfg(feature = "event-store-adapter")]
+use crate::model::RadrootsOutboxEventStoreIngestReceipt;
use crate::model::{
RadrootsOutboxClaimedEvent, RadrootsOutboxDeliveryAttemptRecord,
RadrootsOutboxDeliveryPlanInput, RadrootsOutboxDeliveryPlanRecord,
RadrootsOutboxDeliveryPlanStatus, RadrootsOutboxDeliveryTargetRecord,
RadrootsOutboxDeliveryTargetStatus, RadrootsOutboxEnqueueReceipt, RadrootsOutboxEnqueueStatus,
- RadrootsOutboxEventRecord, RadrootsOutboxEventState, RadrootsOutboxEventStoreIngestReceipt,
- RadrootsOutboxIdempotencyPreflight, RadrootsOutboxOperationInput,
- RadrootsOutboxOperationRecord, RadrootsOutboxOperationStatus, RadrootsOutboxReticulumBehavior,
- RadrootsOutboxReticulumEventRecord, RadrootsOutboxSignedOperationInput,
- RadrootsOutboxSignedTradeMutationInput, RadrootsOutboxStatusSummary,
- RadrootsOutboxTradeMutationInput,
+ RadrootsOutboxEventRecord, RadrootsOutboxEventState, RadrootsOutboxIdempotencyPreflight,
+ RadrootsOutboxOperationInput, RadrootsOutboxOperationRecord, RadrootsOutboxOperationStatus,
+ RadrootsOutboxReticulumBehavior, RadrootsOutboxReticulumEventRecord,
+ RadrootsOutboxSignedOperationInput, RadrootsOutboxSignedTradeMutationInput,
+ RadrootsOutboxStatusSummary, RadrootsOutboxTradeMutationInput,
};
use radroots_event::RadrootsEventKindClass;
use radroots_event::draft::{
@@ -22,6 +23,7 @@ use radroots_event::ids::{RadrootsTradeId, RadrootsTradeMutationId};
use radroots_event::kinds::TRADE_MUTATION_EVENT_KINDS;
use radroots_event::trade::trade_mutation_from_canonical_content;
use radroots_event::wire::RadrootsNip01EventWire;
+#[cfg(feature = "event-store-adapter")]
use radroots_event_store::{
RadrootsEventIngest, RadrootsEventStore, RadrootsTransportObservation,
RadrootsTransportObservationType,
@@ -1209,6 +1211,7 @@ impl RadrootsOutbox {
Ok(changed.rows_affected())
}
+ #[cfg(feature = "event-store-adapter")]
pub async fn ingest_signed_event_local(
&self,
event_store: &RadrootsEventStore,
@@ -1605,6 +1608,7 @@ impl RadrootsOutbox {
Ok(())
}
+ #[cfg(feature = "event-store-adapter")]
async fn claimed_event(
&self,
outbox_event_id: i64,
@@ -3447,6 +3451,7 @@ mod tests {
.expect("generic draft")
}
+ #[cfg(feature = "event-store-adapter")]
fn durable_draft(expected_pubkey: &str, label: &str) -> RadrootsEventDraft {
RadrootsEventDraft::new(
"radroots.social.follow_list.v1",
@@ -8062,6 +8067,7 @@ mod tests {
}
}
+ #[cfg(feature = "event-store-adapter")]
#[tokio::test]
async fn local_signed_event_ingest_records_one_idempotent_local_import_observation() {
let outbox = RadrootsOutbox::open_memory().await.expect("open");
@@ -8133,6 +8139,7 @@ mod tests {
);
}
+ #[cfg(feature = "event-store-adapter")]
#[tokio::test]
async fn local_signed_event_ingest_rejects_negative_observation_time_without_mutation() {
let outbox = RadrootsOutbox::open_memory().await.expect("open");
@@ -8194,6 +8201,7 @@ mod tests {
);
}
+ #[cfg(feature = "event-store-adapter")]
#[tokio::test]
async fn local_ingest_rejects_an_invalid_signature_without_marking_the_outbox_or_store() {
let outbox = RadrootsOutbox::open_memory().await.expect("open");