plugins

package
v0.7.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 22, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

README

Procyon plugin runtime

Procyon plugins are ordinary Go packages linked into the application binary. There is no directory scanning, .so loading or second runtime for private plugins. The application combines project-owned registrations from plugins_local.go with installed registrations from generated plugins_gen.go.

Lifecycle

The registry performs these phases in order:

  1. validate registration names and factories;
  2. instantiate enabled plugins with their namespaced JSON configuration;
  3. validate instance names and Requires dependencies;
  4. reject missing dependencies and cycles, then sort topologically;
  5. run migrations when requested by the application;
  6. register and seal synchronous capabilities;
  7. register typed event handlers;
  8. collect policies and register routes;
  9. start background workers;
  10. stop plugins in reverse dependency order.

plugins.<name>.enabled=false prevents a registered plugin from being instantiated. A required disabled plugin is consequently reported as missing.

Optional interfaces

Existing plugins only need to implement Plugin. New plugins can additionally implement:

  • DependencyDeclarer for Requires() []string;
  • CapabilityRegistrar for synchronous ports;
  • EventRegistrar for event subscriptions before events.Bus.Seal;
  • MigrationProvider for Core-managed versioned migrations;
  • Starter for workers that receive the application cancellation context.

Factories receive Dependencies with the database, logger, event bus, business metrics, UTC clock and shared capability registry. Configuration stays as the separate json.RawMessage factory argument and must be decoded by the owning plugin.

Routes

RegisterRoutes receives the existing public, authenticated and Kratos/RBAC admin groups. It can also receive Routes.Operations, a group on the separate admin server that Core has already protected with RequireAdminKey. Operations is nil when admin-key authentication is not configured, so a plugin must guard its registration:

func (p *Plugin) RegisterRoutes(routes plugins.Routes) {
	if routes.Operations != nil {
		routes.Operations.POST("/maintenance/run", p.runMaintenance)
	}
}

Plugins must not add another admin-key middleware to this group. Route collision detection covers the public, admin and upload servers, including operations routes registered by different plugins.

Capabilities

Capabilities are immediate, synchronous calls. Register a stable interface:

type PlayerLookup interface {
	ExistsAndActive(context.Context, uint) (bool, error)
}

err := plugins.Provide[PlayerLookup](registry, "players", "players.lookup.v1", lookup)

Consumers resolve the interface only after the capability registration phase:

lookup, err := plugins.Resolve[PlayerLookup](registry, "players.lookup.v1")

Duplicate names, missing capabilities, wrong Go types and writes after sealing return explicit errors. Use typed events instead when communicating a fact that has already occurred.

Migrations

A MigrationProvider returns ordered migrations with stable versions:

func (*Plugin) Migrations() []plugins.Migration {
	return []plugins.Migration{{
		Version: "001-create-leagues",
		Up: func(ctx context.Context, tx *gorm.DB) error {
			return tx.WithContext(ctx).AutoMigrate(&League{})
		},
	}}
}

Applied versions are recorded under the composite primary key (plugin_name, migration_version) in plugin_schema_migrations. Each migration is attempted in a GORM transaction. Database-specific DDL rules still apply; notably, MySQL can implicitly commit some schema operations.

Documentation

Overview

Package plugins defines the compile-time plugin contract used by Procyon applications. Plugins can be project-owned Go packages or installed, versioned Go modules. Both are linked into the application binary rather than loaded dynamically at runtime.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrCapabilityNotFound  = errors.New("capability not found")
	ErrCapabilityDuplicate = errors.New("capability already registered")
	ErrCapabilitySealed    = errors.New("capability registry is sealed")
	ErrCapabilityType      = errors.New("capability has unexpected type")
)

Functions

func Provide added in v0.5.0

func Provide[T any](r *CapabilityRegistry, owner, name string, value T) error

Provide registers a typed capability under a stable name.

func Resolve added in v0.5.0

func Resolve[T any](r *CapabilityRegistry, name string) (T, error)

Resolve returns a capability and verifies its Go type.

Types

type CapabilityRegistrar added in v0.5.0

type CapabilityRegistrar interface {
	RegisterCapabilities(*CapabilityRegistry) error
}

CapabilityRegistrar participates in the capability registration phase.

type CapabilityRegistry added in v0.5.0

type CapabilityRegistry struct {
	// contains filtered or unexported fields
}

CapabilityRegistry stores synchronous ports shared by compile-time plugins. Registration happens during application startup and Seal makes it immutable.

func NewCapabilityRegistry added in v0.5.0

func NewCapabilityRegistry() *CapabilityRegistry

func (*CapabilityRegistry) Seal added in v0.5.0

func (r *CapabilityRegistry) Seal()

type Clock added in v0.5.0

type Clock interface {
	Now() time.Time
}

type ConfigResolver added in v0.5.0

type ConfigResolver func(Registration) json.RawMessage

type Dependencies

type Dependencies struct {
	DB           *gorm.DB
	Logger       *zap.Logger
	Events       *events.Bus
	Metrics      *telemetry.BusinessMetrics
	Clock        Clock
	Capabilities *CapabilityRegistry
}

type DependencyDeclarer added in v0.5.0

type DependencyDeclarer interface {
	Requires() []string
}

DependencyDeclarer lets a plugin require other plugins by registration name. Plugins without this interface have no declared dependencies.

type EventRegistrar added in v0.5.0

type EventRegistrar interface {
	RegisterEvents(*events.Bus) error
}

EventRegistrar installs event handlers before the shared event bus is sealed.

type Migration added in v0.5.0

type Migration struct {
	Version string
	Up      func(context.Context, *gorm.DB) error
}

type MigrationProvider added in v0.5.0

type MigrationProvider interface {
	Migrations() []Migration
}

MigrationProvider opts a plugin into Core-managed, versioned migrations. Plugins implementing only Migrate keep their existing migration strategy.

type Plugin

type Plugin interface {
	Name() string
	Migrate(context.Context) error
	Policies() []authz.Policy
	RegisterRoutes(Routes)
	Shutdown(context.Context) error
}

type Registration

type Registration struct {
	Name          string
	Factory       Factory
	DefaultConfig json.RawMessage
}

type Registry added in v0.5.0

type Registry struct {
	// contains filtered or unexported fields
}

Registry composes all project-local and installed plugins through one deterministic lifecycle.

func NewRegistry added in v0.5.0

func NewRegistry(registrations []Registration) (*Registry, error)

func (*Registry) Capabilities added in v0.5.0

func (r *Registry) Capabilities() *CapabilityRegistry

func (*Registry) Instantiate added in v0.5.0

func (r *Registry) Instantiate(ctx context.Context, dependencies Dependencies, resolve ConfigResolver) error

func (*Registry) Migrate added in v0.5.0

func (r *Registry) Migrate(ctx context.Context) error

func (*Registry) Plugins added in v0.5.0

func (r *Registry) Plugins() []Plugin

func (*Registry) Policies added in v0.5.0

func (r *Registry) Policies() []authz.Policy

func (*Registry) RegisterCapabilities added in v0.5.0

func (r *Registry) RegisterCapabilities() error

func (*Registry) RegisterEvents added in v0.5.0

func (r *Registry) RegisterEvents(bus *events.Bus) error

func (*Registry) RegisterRoutes added in v0.5.0

func (r *Registry) RegisterRoutes(routes Routes) error

func (*Registry) Shutdown added in v0.5.0

func (r *Registry) Shutdown(ctx context.Context) error

func (*Registry) Start added in v0.5.0

func (r *Registry) Start(ctx context.Context) error

type Routes

type Routes struct {
	Public        *echo.Group
	Authenticated *echo.Group
	Admin         *echo.Group
	// Operations is the separate admin-server group protected by the configured
	// admin-key middleware. It is nil when admin-key authentication is disabled.
	Operations *echo.Group
	Require    func(domain, object, action string) echo.MiddlewareFunc
	Servers    []*echo.Echo
}

type Starter added in v0.5.0

type Starter interface {
	Start(context.Context) error
}

Starter starts background work after routes and event handlers are registered.

type SystemClock added in v0.5.0

type SystemClock struct{}

func (SystemClock) Now added in v0.5.0

func (SystemClock) Now() time.Time

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL