1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//! # modo::tier
//!
//! Tier-based feature gating for SaaS applications.
//!
//! Requires feature `"tier"`.
//!
//! ```toml
//! [dependencies]
//! modo = { version = "0.6", features = ["tier"] }
//! ```
//!
//! ## Provides
//!
//! - [`TierBackend`] — trait for pluggable tier resolution (app implements)
//! - [`TierResolver`] — concrete wrapper (`Arc<dyn TierBackend>`, cheap to clone)
//! - [`TierInfo`] — resolved tier with feature checks
//! - [`FeatureAccess`] — toggle or limit feature model
//! - [`TierLayer`] — Tower middleware that resolves and injects [`TierInfo`]
//! - [`require_feature()`] — route guard for boolean feature gates
//! - [`require_limit()`] — route guard for usage-limit gates
//! - [`mod@test`] — test helpers (`StaticTierBackend`, `FailingTierBackend`)
//!
//! ## Quick start
//!
//! ```rust,ignore
//! use modo::tier::{TierBackend, TierResolver, TierInfo, TierLayer, require_feature};
//! use axum::{Router, routing::get};
//!
//! # fn example(resolver: TierResolver) {
//! let app: Router = Router::new()
//! .route("/settings/domain", get(|| async { "ok" }))
//! .route_layer(require_feature("custom_domain"))
//! .layer(TierLayer::new(resolver, |parts| {
//! parts.extensions.get::<modo::TenantId>().map(|id| id.as_str().to_owned())
//! }));
//! # }
//! ```
pub use TierInfo;
pub use ;
pub use TierLayer;
pub use ;
/// Test helpers for the tier module.
///
/// Available when running tests or when the `test-helpers` feature is enabled.