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
//! # modo::tier
//!
//! Tier-based feature gating for SaaS applications.
//!
//! Provides:
//!
//! - [`TierBackend`] — trait for pluggable tier resolution (app implements)
//! - [`TierResolver`] — concrete wrapper (`Arc<dyn TierBackend>`, cheap to clone)
//! - [`TierInfo`] — resolved tier with feature checks (also implements
//! [`FromRequestParts`](axum::extract::FromRequestParts) and
//! [`OptionalFromRequestParts`](axum::extract::OptionalFromRequestParts))
//! - [`FeatureAccess`] — toggle or limit feature model
//! - [`TierLayer`] — Tower middleware that resolves and injects [`TierInfo`]
//! (also re-exported as `modo::middlewares::Tier`)
//! - [`require_feature()`] — route guard for boolean feature gates
//! (also re-exported as `modo::guards::require_feature`)
//! - [`require_limit()`] — route guard for usage-limit gates
//! (also re-exported as `modo::guards::require_limit`)
//! - [`test`] — test helpers ([`test::StaticTierBackend`] and
//! [`test::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: axum::Router = axum::Router::new()
//! .route("/settings/domain", get(|| async { "ok" }))
//! .route_layer(require_feature("custom_domain"))
//! .layer(TierLayer::new(resolver, |parts| {
//! parts.extensions.get::<modo::tenant::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.