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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! # nest-rs-guards
//!
//! Transport-spanning guards for nestrs — **one trait, three transports**
//! (HTTP, GraphQL, WS). Declared once with
//! `App::builder().use_guards_global(...)`, every handler on every
//! transport runs through the chain.
//!
//! Plug-in point for the Layer System: every guard is a [`Layer`], so the
//! `#[routes]` / `#[resolver]` / `#[messages]` shapers dedup by `TypeId` when
//! the same guard is declared at multiple sites (global + controller +
//! method) — the broadest [`LayerSite`](nest_rs_core::LayerSite) wins and the
//! rest log a `warn`. The framework runs guards in **declaration order**;
//! [`Layer::priority`] is an opt-in tiebreaker.
//!
//! `#[public]` is not a framework-level skip: the macro attaches a
//! [`Public`](nest_rs_core::Public) marker via the same metadata channel
//! as `#[meta(...)]`, and each guard decides whether to honor it. An
//! `AbilityGuard` may still run on a public route to apply visitor rules;
//! an `AuthGuard` may skip rejection when no token is present.
//!
//! ## Defining a guard
//!
//! Override only the `check_*` method(s) where this guard has work to do —
//! the rest inherit `Ok(())` defaults. `Layer` provides `priority()` /
//! `name()` defaults; override `priority()` only when this guard must beat
//! declaration order.
//!
//! ```rust,ignore
//! use nest_rs_guards::prelude::*;
//!
//! #[injectable]
//! #[derive(Default)]
//! pub struct AuditGuard;
//!
//! impl Layer for AuditGuard {}
//!
//! #[async_trait]
//! impl Guard for AuditGuard {
//! async fn check_http(&self, req: &mut HttpRequest) -> Result<(), Denial> {
//! tracing::info!(target: "audit", method = %req.method(), path = %req.uri(), "request");
//! Ok(())
//! }
//! }
//! ```
//!
//! ## Registering globally
//!
//! ```rust,ignore
//! use nest_rs::App;
//! use nest_rs_guards::{AppBuilderGuardsExt, guard};
//!
//! App::builder()
//! .use_guards_global([guard::<AuthGuard>(), guard::<AuthzGuard>()])
//! .module::<AppModule>()
//! .build().await?
//! .run().await
//! ```
//!
//! Declaration order is the runtime order. If you list `AuthzGuard` before
//! `AuthGuard` the authorization check runs against an empty principal — a
//! name-based heuristic logs a `warn` at boot.
//!
//! ## Marking a handler `#[public]`
//!
//! ```rust,ignore
//! #[get("/health/live")]
//! #[public]
//! async fn live() -> &'static str { "ok" }
//! ```
//!
//! The macro attaches a [`Public`](nest_rs_core::Public) marker to the
//! route. Guards that want to honor it read it via the transport's
//! reflector and adjust their policy.
//!
//! ## Architecture
//!
//! Each shaper macro (`#[routes]`, `#[resolver]`, `#[messages]`) emits a
//! call to one of [`RouteShaper`] / [`run_layered_graphql_chain`]
//! / [`run_layered_ws_chain`] at the start of every handler — the per-route
//! entry is what gives TypeId-level dedup against the global chain. Guards
//! have **no** transport-edge band: the pool executes in the shaper
//! (post-routing, so it reads `#[public]`), at a `Guarded` self-mount's
//! edge (`SelfMountGuardWrap`), or in-band on `/graphql` (the
//! [`GlobalPoolOperationGuard`](dispatch::GlobalPoolOperationGuard)
//! fallback when no bridge is registered).
//!
//! **Larger than its siblings on purpose.** Where `nest-rs-interceptors` /
//! `nest-rs-filters` / `nest-rs-exception-filters` each carry only their own
//! trait + a builder + a registry, this crate also owns the cross-transport
//! [`dispatch`] machinery (the [`RouteShaper`] entry, the layer-chain helpers,
//! the graphql/ws chain runners) that the other three trio members consume.
//! Splitting it would mean duplicating the chain across crates or routing
//! through a fifth — both worse than the asymmetry.
pub use ;
// Cross-transport interceptor / filter / exception-filter trait methods
// (`wrap_graphql`, `wrap_ws`, `filter_graphql`, `filter_ws`,
// `catch_graphql`, `catch_ws`) and the matching continuation types
// (`GraphqlNext`, `WsNext`) now live directly on the base traits in
// `nest-rs-interceptors` / `nest-rs-filters` / `nest-rs-exception-filters`.
// Re-exported here for the historical import path used by the macros.
pub use Denial;
pub use ;
pub use ;
// The dedup logic itself lives in `nest_rs_core::layer_chain` — the single
// home every execution site (route shaper, transport pool folds, graphql/ws
// in-band chains) composes through. Re-exported for macro-emitted code.
pub use layer_chain;
pub use ;
pub use ;
pub use ;
// Re-export dispatch helpers for macro-emitted code.
pub use ;