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

Loading diagram...

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

Loading diagram...

Service Registration Flow

Loading diagram...

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:

Loading diagram...

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

Loading diagram...

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/.


Additional Resources

Was this page helpful?