Skip to main content

systemprompt_traits/
context.rs

1//! Application context, configuration and database handle contracts, and
2//! request-context propagation across HTTP boundaries.
3//!
4//! [`AppContext`] is the runtime entry point the HTTP layer uses to reach
5//! the registered providers (analytics, fingerprint, user) without naming
6//! the concrete runtime type; [`ContextPropagation`] models how
7//! request-scoped state moves across HTTP boundaries; [`ConfigProvider`] and
8//! [`DatabaseHandle`] are the two capabilities the extension framework hands
9//! to downstream code without exposing a concrete pool or profile type.
10//!
11//! Copyright (c) systemprompt.io — Business Source License 1.1.
12//! See <https://systemprompt.io> for licensing details.
13
14use std::sync::Arc;
15
16use crate::analytics::{AnalyticsProvider, FingerprintProvider};
17use crate::auth::UserProvider;
18
19pub trait AppContext: Send + Sync {
20    fn config(&self) -> Arc<dyn ConfigProvider>;
21    fn database_handle(&self) -> Arc<dyn DatabaseHandle>;
22    fn session_provider(&self) -> Option<Arc<dyn crate::SessionProvider>>;
23    fn analytics_provider(&self) -> Option<Arc<dyn AnalyticsProvider>>;
24    fn fingerprint_provider(&self) -> Option<Arc<dyn FingerprintProvider>>;
25    fn user_provider(&self) -> Option<Arc<dyn UserProvider>>;
26}
27
28pub trait InjectContextHeaders {
29    fn inject_headers(&self, headers: &mut http::HeaderMap);
30}
31
32pub type ContextPropagationResult<T> = Result<T, ContextPropagationError>;
33
34#[derive(Debug, thiserror::Error)]
35#[non_exhaustive]
36pub enum ContextPropagationError {
37    #[error("missing header: {0}")]
38    MissingHeader(String),
39
40    #[error("invalid header {name}: {message}")]
41    InvalidHeader { name: String, message: String },
42
43    #[error("invalid context: {0}")]
44    Invalid(String),
45}
46
47pub trait ContextPropagation {
48    fn from_headers(headers: &http::HeaderMap) -> ContextPropagationResult<Self>
49    where
50        Self: Sized;
51
52    fn to_headers(&self) -> http::HeaderMap;
53}
54
55pub trait ConfigProvider: Send + Sync {
56    fn get(&self, key: &str) -> Option<String>;
57    fn database_url(&self) -> &str;
58    fn database_write_url(&self) -> Option<&str> {
59        None
60    }
61    fn system_path(&self) -> &str;
62    fn api_port(&self) -> u16;
63    fn as_any(&self) -> &dyn std::any::Any;
64}
65
66pub trait DatabaseHandle: Send + Sync {
67    fn is_connected(&self) -> bool;
68    fn as_any(&self) -> &dyn std::any::Any;
69}