Plugin System
Temps uses a modular plugin architecture that enables extensibility without modifying core code. All functionality is organized as plugins implementing the TempsPlugin trait.
Overview
The plugin system provides a clean separation of concerns, allowing features to be developed, tested, and maintained independently.
Key Benefits
- Name
Modularity- Description
Each plugin is self-contained with its own services, routes, and configuration
- Name
Extensibility- Description
Add new features without modifying core Temps code
- Name
Type Safety- Description
Type-safe dependency injection through the service registry
- Name
Testability- Description
Plugins can be tested in isolation with mocked dependencies
- Name
OpenAPI Integration- Description
Automatic API documentation generation from plugin routes
Plugin Lifecycle
Plugin Architecture
The TempsPlugin Trait
All plugins implement the TempsPlugin trait, which defines four core methods:
pub trait TempsPlugin: Send + Sync {
/// Unique identifier for this plugin
fn name(&self) -> &'static str;
/// Register services that this plugin provides
fn register_services(
&self,
context: &ServiceRegistrationContext,
) -> Result<(), PluginError>;
/// Configure HTTP routes for this plugin
fn configure_routes(&self, context: &PluginContext) -> Option<PluginRoutes>;
/// Contribute to global OpenAPI schema
fn openapi_schema(&self) -> Option<OpenApi>;
}
Plugin Components
Service Registration Flow
Key Plugins
Temps includes 40+ plugins that provide core functionality:
- Name
ProxyPlugin- Description
HTTP/HTTPS request routing, load balancing, and analytics collection
- Name
DeployerPlugin- Description
Container building, CI/CD pipeline, and deployment management
- Name
DomainsPlugin- Description
DNS management and TLS certificate provisioning
- Name
AnalyticsPlugin- Description
Event tracking, metrics collection, and visitor analytics
- Name
AuthPlugin- Description
User authentication, authorization, and session management
- Name
ErrorTrackingPlugin- Description
Sentry-compatible error tracking and monitoring
- Name
BlobPlugin- Description
Object storage and file management
- Name
KVPlugin- Description
Key-value store for caching and state management
Plugin Dependencies
Plugins can depend on services from other plugins:
Service Registration
Type-Safe Service Lookup
The service registry uses Rust's type system for compile-time safety:
// During plugin initialization
let service = context.get_service::<MyService>();
// Type: Option<Arc<MyService>>
// Use the service
if let Some(svc) = service {
let result = svc.do_something().await;
}
Service Dependencies
Plugins can request services from other plugins during registration:
async fn register_services(
&self,
context: &ServiceRegistrationContext,
) -> Result<(), PluginError> {
// Get database connection (from core)
let db = context.get_service::<DbConnection>()
.ok_or_else(|| PluginError::ServiceNotFound {
service_type: "DbConnection".to_string(),
})?;
// Get analytics service (from AnalyticsPlugin)
let analytics = context.get_service::<AnalyticsService>()
.ok_or_else(|| PluginError::ServiceNotFound {
service_type: "AnalyticsService".to_string(),
})?;
// Create and register your service
let service = Arc::new(MyService::new(db, analytics));
context.register_service(service);
Ok(())
}
Service Registration Flow
Route Configuration
Route Naming Convention
- Admin APIs:
/api/admin/* - Plugin APIs:
/api/<plugin-name>/* - Public APIs:
/api/public/* - Internal APIs:
/api/_temps/*(Temps reserved)
Example Route Configuration
fn configure_routes(&self, context: &PluginContext) -> Option<PluginRoutes> {
// Get your service from registry
let service = context.get_service::<MyService>()?;
// Create an Axum router
let router = axum::Router::new()
.route("/api/my-plugin/status", axum::routing::get(status_handler))
.route("/api/my-plugin/items", axum::routing::get(list_items))
.with_state(Arc::new(service.clone()));
Some(PluginRoutes::new(router))
}
OpenAPI Integration
Plugins automatically contribute to the global OpenAPI schema:
fn openapi_schema(&self) -> Option<OpenApi> {
// Define your API documentation
Some(MyApiDoc::openapi())
}
All plugin schemas are merged into one global schema accessible at /swagger-ui/.