feat(tinyplace): default relay endpoint to follow OPENHUMAN_APP_ENV (#4611)

This commit is contained in:
Steven Enamakel
2026-07-06 14:50:56 -07:00
committed by GitHub
parent 9b84f96845
commit 2d310b838e
2 changed files with 96 additions and 13 deletions
+3 -2
View File
@@ -437,8 +437,9 @@ RUST_BACKTRACE=1
# tiny.place Agent World integration
# ---------------------------------------------------------------------------
# [optional] Base URL for the tiny.place backend API.
# Default: https://api.tiny.place (production)
# Set to https://staging-api.tiny.place to test against staging.
# When unset, the default follows OPENHUMAN_APP_ENV: a `staging` app env uses
# https://staging-api.tiny.place, otherwise https://api.tiny.place (production).
# Set this to pin an explicit host — it always overrides the app-env default.
# TINYPLACE_API_BASE_URL=https://staging-api.tiny.place
# ---------------------------------------------------------------------------
+93 -11
View File
@@ -17,26 +17,36 @@ use tinyplace::{LocalSigner, TinyPlaceClient, TinyPlaceClientOptions};
const LOG_PREFIX: &str = "[tinyplace]";
/// Production tiny.place relay/API host — the default outside a staging build.
const TINYPLACE_PROD_BASE_URL: &str = "https://api.tiny.place";
/// Staging tiny.place relay/API host — the default when the OpenHuman app env
/// is `staging` and no explicit `TINYPLACE_API_BASE_URL` is set.
const TINYPLACE_STAGING_BASE_URL: &str = "https://staging-api.tiny.place";
/// Shared tiny.place state: lazy-built client keyed to one base URL.
pub(crate) struct TinyPlaceState {
/// Lazily initialised on first [`TinyPlaceState::client`] call.
client: OnceCell<TinyPlaceClient>,
/// Backend base URL (from `TINYPLACE_API_BASE_URL` env or staging default).
/// Backend base URL (from `TINYPLACE_API_BASE_URL`, else app-env default).
pub(crate) base_url: String,
}
impl TinyPlaceState {
/// Build from the environment. `TINYPLACE_API_BASE_URL` overrides the
/// default production endpoint (set it to the staging host for testing).
/// Build from the environment.
///
/// Base URL precedence: an explicit `TINYPLACE_API_BASE_URL` always wins;
/// otherwise the default follows the OpenHuman app environment so a staging
/// build talks to staging tiny.place and a production build talks to prod
/// (previously the default was hardcoded to prod regardless of app env,
/// which silently 404'd a staging instance against prod tiny.place).
pub(crate) fn from_env() -> Self {
// Treat a blank/whitespace override as unset so it can't produce an
// invalid base_url (mirrors wallet::defaults env handling).
let base_url = std::env::var("TINYPLACE_API_BASE_URL")
.ok()
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
.unwrap_or_else(|| "https://api.tiny.place".to_string());
log::debug!("{LOG_PREFIX} state created base_url={base_url}");
let explicit = std::env::var("TINYPLACE_API_BASE_URL").ok();
let app_env = crate::api::config::app_env_from_env();
let base_url = resolve_base_url(explicit.as_deref(), app_env.as_deref());
log::debug!(
"{LOG_PREFIX} state created base_url={base_url} app_env={}",
app_env.as_deref().unwrap_or("<unset>")
);
Self {
client: OnceCell::new(),
base_url,
@@ -71,3 +81,75 @@ impl TinyPlaceState {
.await
}
}
/// Resolve the tiny.place base URL from an explicit override + app env.
///
/// A non-blank explicit value (from `TINYPLACE_API_BASE_URL`) always wins.
/// Blank/whitespace is treated as unset (mirrors `wallet::defaults` handling)
/// so it can't produce an invalid base URL. With no explicit override, the
/// default tracks the app environment: staging → staging host, else prod.
fn resolve_base_url(explicit: Option<&str>, app_env: Option<&str>) -> String {
if let Some(url) = explicit.map(str::trim).filter(|value| !value.is_empty()) {
return url.to_string();
}
default_base_url_for_app_env(app_env).to_string()
}
/// The tiny.place host to default to for a given OpenHuman app environment.
fn default_base_url_for_app_env(app_env: Option<&str>) -> &'static str {
if crate::api::config::is_staging_app_env(app_env) {
TINYPLACE_STAGING_BASE_URL
} else {
TINYPLACE_PROD_BASE_URL
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn explicit_override_always_wins() {
// Even a staging app env must not override an explicit URL.
assert_eq!(
resolve_base_url(Some("https://custom.example"), Some("staging")),
"https://custom.example"
);
assert_eq!(
resolve_base_url(Some(" https://trimmed.example "), None),
"https://trimmed.example"
);
}
#[test]
fn blank_override_falls_through_to_app_env_default() {
// Blank/whitespace is treated as unset.
assert_eq!(
resolve_base_url(Some(" "), Some("staging")),
TINYPLACE_STAGING_BASE_URL
);
assert_eq!(resolve_base_url(Some(""), None), TINYPLACE_PROD_BASE_URL);
}
#[test]
fn default_follows_app_env() {
assert_eq!(
default_base_url_for_app_env(Some("staging")),
TINYPLACE_STAGING_BASE_URL
);
assert_eq!(
default_base_url_for_app_env(Some("STAGING")),
TINYPLACE_STAGING_BASE_URL
);
assert_eq!(
default_base_url_for_app_env(Some("production")),
TINYPLACE_PROD_BASE_URL
);
// Unknown / unset env defaults to prod.
assert_eq!(default_base_url_for_app_env(None), TINYPLACE_PROD_BASE_URL);
assert_eq!(
default_base_url_for_app_env(Some("dev")),
TINYPLACE_PROD_BASE_URL
);
}
}