commit 8980ce18804175ea0442ec8b8e27485f96cf9fd7
parent 5c9b7fc8242415722aa1845a751dd45879715c2e
Author: triesap <tyson@radroots.org>
Date: Fri, 26 Jun 2026 05:58:17 +0000
sdk: expose geonames runtime asset API
Diffstat:
8 files changed, 174 insertions(+), 13 deletions(-)
diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml
@@ -58,8 +58,10 @@ runtime = [
"dep:hex",
"dep:radroots_authority",
"dep:radroots_event_store",
+ "dep:radroots_geocoder",
"dep:radroots_outbox",
"dep:radroots_relay_transport",
+ "dep:radroots_runtime_paths",
"dep:sha2",
"dep:sqlx",
"dep:uuid",
@@ -104,9 +106,11 @@ radroots_authority = { workspace = true, optional = true, default-features = fal
radroots_event_store = { workspace = true, optional = true, default-features = false }
radroots_events = { workspace = true, default-features = false }
radroots_events_codec = { workspace = true, default-features = false }
+radroots_geocoder = { workspace = true, optional = true }
radroots_outbox = { workspace = true, optional = true, default-features = false }
radroots_publish_proxy_protocol = { workspace = true, optional = true, default-features = false }
radroots_relay_transport = { workspace = true, optional = true, default-features = false }
+radroots_runtime_paths = { workspace = true, optional = true, default-features = false }
radroots_trade = { workspace = true, default-features = false }
radroots_identity = { workspace = true, optional = true, default-features = false }
radroots_nostr = { workspace = true, optional = true, default-features = false }
diff --git a/crates/sdk/src/geonames.rs b/crates/sdk/src/geonames.rs
@@ -0,0 +1,89 @@
+#![cfg(feature = "runtime")]
+
+use std::path::{Path, PathBuf};
+
+pub use radroots_geocoder::{
+ GEONAMES_1_0_ASSET, GEONAMES_ASSET_BYTE_SIZE, GEONAMES_ASSET_FILE_NAME, GEONAMES_ASSET_HOST,
+ GEONAMES_ASSET_SHA256, GEONAMES_ASSET_URL, GEONAMES_ASSET_VERSION, GeoNamesAssetFetcher,
+ GeoNamesAssetSpec, GeoNamesAssetState, GeoNamesAssetStatus, GeoNamesBlockingHttpFetcher,
+ Geocoder, GeocoderCountryListResult, GeocoderError, GeocoderPoint, GeocoderReverseOptions,
+ GeocoderReverseResult,
+};
+use radroots_geocoder::{
+ ensure_default_geonames_asset_in_cache_root, ensure_geonames_asset_in_cache_root_with_fetcher,
+ inspect_default_geonames_asset_in_cache_root, inspect_geonames_asset_path,
+};
+use radroots_runtime_paths::{
+ default_shared_geonames_database_path_from_cache_root,
+ default_shared_geonames_root_from_cache_root,
+};
+
+pub fn radroots_sdk_geonames_database_path_from_cache_root(
+ cache_root: impl AsRef<Path>,
+) -> PathBuf {
+ default_shared_geonames_database_path_from_cache_root(cache_root, GEONAMES_ASSET_VERSION)
+}
+
+pub fn radroots_sdk_geonames_database_path_from_cache_root_for_version(
+ cache_root: impl AsRef<Path>,
+ version: &str,
+) -> PathBuf {
+ default_shared_geonames_database_path_from_cache_root(cache_root, version)
+}
+
+pub fn radroots_sdk_geonames_root_from_cache_root(cache_root: impl AsRef<Path>) -> PathBuf {
+ default_shared_geonames_root_from_cache_root(cache_root)
+}
+
+pub fn radroots_sdk_inspect_geonames_database_in_cache_root(
+ cache_root: impl AsRef<Path>,
+) -> Result<GeoNamesAssetStatus, GeocoderError> {
+ inspect_default_geonames_asset_in_cache_root(cache_root)
+}
+
+pub fn radroots_sdk_inspect_geonames_database_path_with_spec(
+ path: impl AsRef<Path>,
+ spec: &GeoNamesAssetSpec,
+) -> Result<GeoNamesAssetStatus, GeocoderError> {
+ inspect_geonames_asset_path(path, spec)
+}
+
+pub fn radroots_sdk_ensure_geonames_database_in_cache_root(
+ cache_root: impl AsRef<Path>,
+) -> Result<GeoNamesAssetStatus, GeocoderError> {
+ ensure_default_geonames_asset_in_cache_root(cache_root)
+}
+
+pub fn radroots_sdk_ensure_geonames_database_in_cache_root_with_fetcher<F>(
+ cache_root: impl AsRef<Path>,
+ fetcher: &F,
+) -> Result<GeoNamesAssetStatus, GeocoderError>
+where
+ F: GeoNamesAssetFetcher,
+{
+ ensure_geonames_asset_in_cache_root_with_fetcher(cache_root, &GEONAMES_1_0_ASSET, fetcher)
+}
+
+pub fn radroots_sdk_ensure_geonames_database_in_cache_root_with_spec_and_fetcher<F>(
+ cache_root: impl AsRef<Path>,
+ spec: &GeoNamesAssetSpec,
+ fetcher: &F,
+) -> Result<GeoNamesAssetStatus, GeocoderError>
+where
+ F: GeoNamesAssetFetcher,
+{
+ ensure_geonames_asset_in_cache_root_with_fetcher(cache_root, spec, fetcher)
+}
+
+pub fn radroots_sdk_open_verified_geonames_database(
+ path: impl AsRef<Path>,
+) -> Result<Geocoder, GeocoderError> {
+ Geocoder::open_verified_geonames_asset(path, &GEONAMES_1_0_ASSET)
+}
+
+pub fn radroots_sdk_open_verified_geonames_database_with_spec(
+ path: impl AsRef<Path>,
+ spec: &GeoNamesAssetSpec,
+) -> Result<Geocoder, GeocoderError> {
+ Geocoder::open_verified_geonames_asset(path, spec)
+}
diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs
@@ -19,6 +19,8 @@ mod farm;
#[cfg(feature = "runtime")]
mod farms_runtime;
#[cfg(feature = "runtime")]
+mod geonames;
+#[cfg(feature = "runtime")]
mod idempotency;
#[cfg(feature = "identity-models")]
mod identity;
@@ -54,6 +56,23 @@ pub use crate::farms_runtime::{
FarmPreparePublishRequest, FarmPublishPlan,
};
#[cfg(feature = "runtime")]
+pub use crate::geonames::{
+ GEONAMES_1_0_ASSET, GEONAMES_ASSET_BYTE_SIZE, GEONAMES_ASSET_FILE_NAME, GEONAMES_ASSET_HOST,
+ GEONAMES_ASSET_SHA256, GEONAMES_ASSET_URL, GEONAMES_ASSET_VERSION, GeoNamesAssetFetcher,
+ GeoNamesAssetSpec, GeoNamesAssetState, GeoNamesAssetStatus, GeoNamesBlockingHttpFetcher,
+ Geocoder, GeocoderCountryListResult, GeocoderError, GeocoderPoint, GeocoderReverseOptions,
+ GeocoderReverseResult, radroots_sdk_ensure_geonames_database_in_cache_root,
+ radroots_sdk_ensure_geonames_database_in_cache_root_with_fetcher,
+ radroots_sdk_ensure_geonames_database_in_cache_root_with_spec_and_fetcher,
+ radroots_sdk_geonames_database_path_from_cache_root,
+ radroots_sdk_geonames_database_path_from_cache_root_for_version,
+ radroots_sdk_geonames_root_from_cache_root,
+ radroots_sdk_inspect_geonames_database_in_cache_root,
+ radroots_sdk_inspect_geonames_database_path_with_spec,
+ radroots_sdk_open_verified_geonames_database,
+ radroots_sdk_open_verified_geonames_database_with_spec,
+};
+#[cfg(feature = "runtime")]
pub use crate::idempotency::{SDK_IDEMPOTENCY_KEY_MAX_LEN, SdkIdempotencyKey};
#[cfg(feature = "runtime")]
pub use crate::listings_runtime::{
diff --git a/crates/sdk/tests/facade.rs b/crates/sdk/tests/facade.rs
@@ -10,7 +10,7 @@ use radroots_events::kinds::{
};
use radroots_events::listing::{
RadrootsListing, RadrootsListingAvailability, RadrootsListingBin,
- RadrootsListingDeliveryMethod, RadrootsListingLocation, RadrootsListingProduct,
+ RadrootsListingDeliveryMethod, RadrootsListingProduct, RadrootsListingPublicLocation,
RadrootsListingStatus,
};
use radroots_events::order::{
@@ -103,14 +103,12 @@ fn sample_listing() -> RadrootsListing {
status: RadrootsListingStatus::Active,
}),
delivery_method: Some(RadrootsListingDeliveryMethod::Pickup),
- location: Some(RadrootsListingLocation {
+ location: Some(RadrootsListingPublicLocation {
primary: "North Farm".into(),
city: None,
region: None,
country: None,
- lat: None,
- lng: None,
- geohash: None,
+ geohash: "9q8yy".into(),
}),
images: None,
}
diff --git a/crates/sdk/tests/geonames.rs b/crates/sdk/tests/geonames.rs
@@ -0,0 +1,48 @@
+#![cfg(feature = "runtime")]
+
+use radroots_sdk::{
+ GEONAMES_ASSET_HOST, GEONAMES_ASSET_VERSION, GeoNamesAssetState,
+ radroots_sdk_geonames_database_path_from_cache_root,
+ radroots_sdk_geonames_database_path_from_cache_root_for_version,
+ radroots_sdk_geonames_root_from_cache_root,
+ radroots_sdk_inspect_geonames_database_in_cache_root,
+};
+
+#[test]
+fn sdk_geonames_facade_resolves_shared_cache_paths_and_reports_missing_state() {
+ let tempdir = tempfile::tempdir().expect("tempdir");
+ let cache_root = tempdir.path().join("cache");
+
+ assert_eq!(GEONAMES_ASSET_HOST, "assets.radroots.io");
+ assert_eq!(GEONAMES_ASSET_VERSION, "1.0");
+ assert_eq!(
+ radroots_sdk_geonames_root_from_cache_root(&cache_root),
+ cache_root.join("shared").join("geonames")
+ );
+ assert_eq!(
+ radroots_sdk_geonames_database_path_from_cache_root(&cache_root),
+ cache_root
+ .join("shared")
+ .join("geonames")
+ .join("geonames-1.0.db")
+ );
+ assert_eq!(
+ radroots_sdk_geonames_database_path_from_cache_root_for_version(&cache_root, "1.1"),
+ cache_root
+ .join("shared")
+ .join("geonames")
+ .join("geonames-1.1.db")
+ );
+
+ let status =
+ radroots_sdk_inspect_geonames_database_in_cache_root(&cache_root).expect("inspection");
+ assert_eq!(status.state, GeoNamesAssetState::Missing);
+ assert_eq!(status.version, "1.0");
+ assert_eq!(
+ status.path,
+ cache_root
+ .join("shared")
+ .join("geonames")
+ .join("geonames-1.0.db")
+ );
+}
diff --git a/crates/trade_bindings/src/dto.rs b/crates/trade_bindings/src/dto.rs
@@ -74,7 +74,10 @@ imported_ts_type!(
"RadrootsListingDeliveryMethod"
);
imported_ts_type!(RadrootsListingImageImport, "RadrootsListingImage");
-imported_ts_type!(RadrootsListingLocationImport, "RadrootsListingLocation");
+imported_ts_type!(
+ RadrootsListingPublicLocationImport,
+ "RadrootsListingPublicLocation"
+);
imported_ts_type!(RadrootsListingProductImport, "RadrootsListingProduct");
imported_ts_type!(RadrootsNostrEventPtrImport, "RadrootsNostrEventPtr");
imported_ts_type!(RadrootsPlotRefImport, "RadrootsPlotRef");
@@ -207,7 +210,7 @@ pub struct RadrootsTradeListingProjection {
pub inventory_available: Option<RadrootsCoreDecimalImport>,
pub availability: Option<RadrootsListingAvailabilityImport>,
pub delivery_method: Option<RadrootsListingDeliveryMethodImport>,
- pub location: Option<RadrootsListingLocationImport>,
+ pub location: Option<RadrootsListingPublicLocationImport>,
pub images: Option<Vec<RadrootsListingImageImport>>,
pub order_count: u32,
pub open_order_count: u32,
diff --git a/crates/trade_bindings/src/lib.rs b/crates/trade_bindings/src/lib.rs
@@ -35,8 +35,8 @@ pub const TRADE_TYPE_INVENTORY: &[TradeTypeInventoryEntry] = &[
event_import("RadrootsListingAvailability"),
event_import("RadrootsListingBin"),
event_import("RadrootsListingDeliveryMethod"),
- event_import("RadrootsListingLocation"),
event_import("RadrootsListingProduct"),
+ event_import("RadrootsListingPublicLocation"),
event_import("RadrootsListingStatus"),
local_shape("RadrootsTradeFacetCount"),
source_root("RadrootsTradeListing"),
@@ -181,8 +181,8 @@ mod tests {
"RadrootsListingAvailability",
"RadrootsListingBin",
"RadrootsListingDeliveryMethod",
- "RadrootsListingLocation",
"RadrootsListingProduct",
+ "RadrootsListingPublicLocation",
"RadrootsListingStatus",
"RadrootsTradeFacetCount",
"RadrootsTradeListing",
@@ -230,8 +230,8 @@ mod tests {
"RadrootsListingAvailability",
"RadrootsListingBin",
"RadrootsListingDeliveryMethod",
- "RadrootsListingLocation",
"RadrootsListingProduct",
+ "RadrootsListingPublicLocation",
"RadrootsListingStatus",
"RadrootsTradeMessageType",
"RadrootsTradeOrderStatus",
diff --git a/tools/sdk_xtask_import/src/dto_roots.rs b/tools/sdk_xtask_import/src/dto_roots.rs
@@ -262,8 +262,8 @@ fn trade_import_options(mut options: DtoRegistryRenderOptions) -> DtoRegistryRen
"RadrootsListingBin",
"RadrootsListingDeliveryMethod",
"RadrootsListingImage",
- "RadrootsListingLocation",
"RadrootsListingProduct",
+ "RadrootsListingPublicLocation",
"RadrootsListingStatus",
"RadrootsNostrEventPtr",
"RadrootsPlotRef",
@@ -380,7 +380,7 @@ mod tests {
"RadrootsDocument",
"RadrootsDocumentSubject",
"RadrootsFarm",
- "RadrootsFarmLocation",
+ "RadrootsFarmPublicLocation",
"RadrootsFarmRef",
"RadrootsFollow",
"RadrootsFollowProfile",
@@ -404,9 +404,9 @@ mod tests {
"RadrootsListingDeliveryMethod",
"RadrootsListingImage",
"RadrootsListingImageSize",
- "RadrootsListingLocation",
"RadrootsListingProduct",
"RadrootsListingProductTagKeys",
+ "RadrootsListingPublicLocation",
"RadrootsListingStatus",
"RadrootsMessage",
"RadrootsMessageFile",