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
//! Shared HTTP server runtime for Polaris products.
//!
//! `polaris_app` provides an axum-based HTTP server that integrates with the
//! Polaris plugin lifecycle. Plugins register route fragments during `build()`
//! via the [`HttpRouter`] API, and [`AppPlugin`] merges and serves them with
//! Tower middleware (CORS, tracing, request ID).
//!
//! This crate is the shared infrastructure for `polaris-http`, `polaris-mcp`
//! (SSE transport), and any future product that needs an HTTP interface.
//!
//! # Architecture
//!
//! ```text
//! AppPlugin (axum server lifecycle)
//! ├── HttpRouter API (route and auth registration)
//! ├── WsRouter API (WebSocket route registration, `ws` feature)
//! ├── AppConfig (host, port, CORS)
//! ├── ServerHandle (shutdown signal, API)
//! ├── AuthProvider trait (pluggable authentication)
//! ├── Tower middleware (CORS, tracing, request ID, auth)
//! └── RequestContextPlugin (trace/correlation/request IDs)
//! ```
//!
//! # Request Context
//!
//! [`RequestContext`] carries `trace_id`, `correlation_id`, and `request_id`
//! for observability and propagation. Two entry points:
//!
//! - **Custom axum handlers** — [`RequestContext`] implements
//! [`FromRequestParts`](axum::extract::FromRequestParts) with
//! `Rejection = Infallible`, so handlers can accept it as an argument.
//! - **Session graphs** — handlers insert [`HttpHeaders`] into the setup
//! closure, and [`RequestContextPlugin`]'s `OnGraphStart` hook turns them
//! into a [`RequestContext`] that systems read via `Res<RequestContext>`.
//!
//! The pure core is [`RequestContext::from_headers`], lenient by design:
//! missing headers become `None`, never a rejection.
//!
//! # Feature Flags
//!
//! - `ws` — enables [`WsRouter`] for plugin-contributed WebSocket routes
//!
//! # Quick Start
//!
//! ```no_run
//! use polaris_system::server::Server;
//! use polaris_app::{AppPlugin, AppConfig, HttpRouter};
//! use axum::{Router, routing::get};
//!
//! let mut server = Server::new();
//! server.add_plugins(
//! AppPlugin::new(AppConfig::new().with_port(8080))
//! );
//! // Other plugins register routes via HttpRouter in their build()
//! ```
//!
//! # Plugin Route Registration
//!
//! Any plugin that depends on [`AppPlugin`] can register routes:
//!
//! ```no_run
//! use polaris_system::plugin::{Plugin, PluginId, Version};
//! use polaris_system::server::Server;
//! use polaris_app::{AppPlugin, HttpRouter};
//! use axum::{Router, routing::get};
//!
//! struct HealthPlugin;
//!
//! impl Plugin for HealthPlugin {
//! const ID: &'static str = "myapp::health";
//! const VERSION: Version = Version::new(0, 1, 0);
//!
//! fn build(&self, server: &mut Server) {
//! let router = Router::new().route("/healthz", get(|| async { "ok" }));
//! server.api::<HttpRouter>()
//! .expect("AppPlugin must be added first")
//! .add_routes(router);
//! }
//!
//! fn dependencies(&self) -> Vec<PluginId> {
//! vec![PluginId::of::<AppPlugin>()]
//! }
//! }
//! ```
//!
//! # See Also
//!
//! For the full framework guide, deferred router construction
//! (`add_routes_with`), and HTTP integration patterns, see the
//! [`polaris-ai` crate documentation](https://docs.rs/polaris-ai).
pub use AuthProvider;
pub use AppConfig;
pub use ;
pub use ;
pub use ;
pub use HttpRouter;
pub use WsRouter;