///|
fn require(condition : Bool, message : String) -> Unit {
if !condition {
abort(message)
}
}
///|
/// The SDK routes calls; the injected adapter owns the flag decisions.
fn label_provider(
name : String,
label : String,
retired : Array[String],
) -> @feature.Provider {
@feature.Provider::new(
name,
(key, _, default, _) => {
if key == "checkout-theme" {
@feature.Resolution::success(
@feature.FlagValue::String(label),
reason="STATIC",
variant=Some(label),
)
} else {
@feature.Resolution::failure(
default,
@feature.SdkError::new(FlagNotFound, "unknown flag: " + key),
)
}
},
shutdown=Some(provider => {
retired.push(provider.name())
println("shutdown: " + provider.name())
Ok(())
}),
)
}
///|
fn show_routes(
stage : String,
alpha : @feature.Client,
beta : @feature.Client,
guest : @feature.Client,
) -> Unit {
println(
stage +
": alpha=" +
alpha.string_value("checkout-theme", "safe") +
" beta=" +
beta.string_value("checkout-theme", "safe") +
" guest=" +
guest.string_value("checkout-theme", "safe"),
)
}
///|
fn main {
let sdk = @feature.Sdk::new()
let retired : Array[String] = []
// Construct clients once: their domain bindings are resolved on every call.
let alpha = sdk.client(domain="tenant-alpha", name="checkout")
let beta = sdk.client(domain="tenant-beta", name="checkout")
let guest = sdk.client(domain="guest", name="checkout")
let default_v1 = label_provider("default-v1", "classic", retired)
sdk.set_provider(default_v1).unwrap()
let shared = label_provider("enterprise-shared", "enterprise", retired)
sdk.set_provider(shared, domain="tenant-alpha").unwrap()
sdk.set_provider(shared, domain="tenant-beta").unwrap()
require(
sdk.registered_domains().length() == 3,
"guest must not create a provider binding",
)
show_routes("initial", alpha, beta, guest)
require(
alpha.string_value("checkout-theme", "safe") == "enterprise",
"alpha binding",
)
require(
beta.string_value("checkout-theme", "safe") == "enterprise",
"beta binding",
)
require(
guest.string_value("checkout-theme", "safe") == "classic",
"unbound domain fallback",
)
let ready_events : Array[String] = []
let listener = alpha.on(ProviderReady, event => {
let line = event.provider_name + "@" + event.domain.unwrap()
ready_events.push(line)
println("alpha ready: " + line)
Ok(())
})
let dedicated = label_provider("alpha-v2", "modern", retired)
sdk.set_provider(dedicated, domain="tenant-alpha").unwrap()
show_routes("replace alpha", alpha, beta, guest)
require(
alpha.string_value("checkout-theme", "safe") == "modern",
"live client replacement",
)
require(
beta.string_value("checkout-theme", "safe") == "enterprise",
"other domain isolation",
)
require(
shared.status() == @feature.ProviderStatus::Ready,
"shared provider retired too early",
)
require(retired.length() == 0, "still-bound shared provider must stay alive")
sdk.clear_domain("tenant-beta").unwrap()
show_routes("clear beta", alpha, beta, guest)
require(
shared.status() == @feature.ProviderStatus::Shutdown,
"last shared binding must retire",
)
require(retired == ["enterprise-shared"], "shared shutdown must run once")
require(
beta.string_value("checkout-theme", "safe") == "classic",
"cleared domain fallback",
)
let default_v2 = label_provider("default-v2", "accessible", retired)
sdk.set_provider(default_v2).unwrap()
show_routes("replace default", alpha, beta, guest)
require(
alpha.string_value("checkout-theme", "safe") == "modern",
"explicit binding must survive",
)
require(
beta.string_value("checkout-theme", "safe") == "accessible",
"fallback client stays live",
)
require(
guest.string_value("checkout-theme", "safe") == "accessible",
"guest follows new default",
)
require(
default_v1.status() == @feature.ProviderStatus::Shutdown,
"old default must retire",
)
sdk.clear_domain("tenant-alpha").unwrap()
show_routes("clear alpha", alpha, beta, guest)
require(
alpha.string_value("checkout-theme", "safe") == "accessible",
"alpha returns to default",
)
require(
dedicated.status() == @feature.ProviderStatus::Shutdown,
"dedicated provider retired",
)
require(
ready_events == ["enterprise-shared@tenant-alpha", "alpha-v2@tenant-alpha"],
"ready replay and replacement notification",
)
require(alpha.off(listener), "listener removal")
sdk.shutdown().unwrap()
sdk.shutdown().unwrap()
require(
retired == ["enterprise-shared", "default-v1", "alpha-v2", "default-v2"],
"one shutdown per provider",
)
let stopped = guest.string_details("checkout-theme", "safe")
require(
stopped.value == "safe" &&
stopped.details.error is Some({ code: ProviderNotReady, .. }),
"closed SDK must return default",
)
println("after shutdown: " + stopped.details.to_json().stringify())
require(
sdk.take_diagnostics().length() == 0,
"unexpected lifecycle diagnostics",
)
}