plugin

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

Documentation

Overview

Package plugin re-exports the public plugin types from pkg/plugin.

This allows internal code to continue importing "internal/platform/plugin" unchanged while the canonical type definitions live in the public pkg/plugin package, accessible to external plugin authors.

Index

Constants

View Source
const HealthPingFunc = "__health_ping__"

HealthPingFunc is the reserved function name the manager probes against every loaded plugin to check liveness.

The probe uses the existing Plugin.Call path — no protocol changes, no mandatory plugin-side handler. A plugin that doesn't recognise this function name will return an "unknown function" error, which the health checker treats as HEALTHY (any quick response means the gRPC/net-rpc channel is alive and the plugin process is responsive). Only a context-deadline-exceeded error counts as a failure — that's what distinguishes a zombie plugin from a merely unhelpful one.

Plugins that want to surface rich health info can implement a handler for this name and return a JSON object — the manager stores it on PluginHealth.Payload so admin UIs can render it. Plugins that don't implement it remain healthy as before; the payload is just empty.

Variables

View Source
var DefaultResourcePolicy = pkgplugin.DefaultResourcePolicy

DefaultResourcePolicy re-exports the default policy constructor.

View Source
var PluginCallerKey = pluginCallerKeyType{}

PluginCallerKey is the context key for tracking which plugin is making a call.

View Source
var PluginLanguageKey = pluginLangKeyType{}

Functions

func RegisterPluginJobs

func RegisterPluginJobs(mgr *Manager, sched PlatformScheduler) int

RegisterPluginJobs registers all plugin-defined jobs with the scheduler. Call this after plugins are loaded and the scheduler is created.

func SetGlobalManager

func SetGlobalManager(m *Manager)

SetGlobalManager sets the plugin manager for file storage policy lookups.

func SetTemplateOverrides

func SetTemplateOverrides(registry *TemplateOverrideRegistry)

SetTemplateOverrides sets the global template override registry.

func SetTemplatePluginManager

func SetTemplatePluginManager(mgr *Manager)

SetTemplatePluginManager sets the plugin manager for template tags. Call this during app initialization after creating the plugin manager.

Types

type CascadeSpec

type CascadeSpec = pkgplugin.CascadeSpec

type CustomFieldFilter

type CustomFieldFilter = pkgplugin.CustomFieldFilter

type CustomFieldSpec

type CustomFieldSpec = pkgplugin.CustomFieldSpec

type DefaultHostAPI

type DefaultHostAPI struct {
}

DefaultHostAPI provides a basic implementation of HostAPI. In production, this would be wired to actual database, cache, etc.

func NewDefaultHostAPI

func NewDefaultHostAPI() *DefaultHostAPI

NewDefaultHostAPI creates a new default host API.

func (*DefaultHostAPI) CacheDelete

func (h *DefaultHostAPI) CacheDelete(ctx context.Context, key string) error

CacheDelete removes a value from cache.

func (*DefaultHostAPI) CacheGet

func (h *DefaultHostAPI) CacheGet(ctx context.Context, key string) ([]byte, bool, error)

CacheGet retrieves a value from cache.

func (*DefaultHostAPI) CacheSet

func (h *DefaultHostAPI) CacheSet(ctx context.Context, key string, value []byte, ttlSeconds int) error

CacheSet stores a value in cache.

func (*DefaultHostAPI) CallPlugin

func (h *DefaultHostAPI) CallPlugin(ctx context.Context, pluginName, fn string, args json.RawMessage) (json.RawMessage, error)

CallPlugin calls a function in another plugin.

func (*DefaultHostAPI) ConfigGet

func (h *DefaultHostAPI) ConfigGet(ctx context.Context, key string) (string, error)

ConfigGet retrieves a configuration value.

func (*DefaultHostAPI) CustomFieldsGet

func (h *DefaultHostAPI) CustomFieldsGet(ctx context.Context, entityType string, objectID int64, fields []string) (map[string]any, error)

CustomFieldsGet retrieves custom field values for an entity.

func (*DefaultHostAPI) CustomFieldsQuery

func (h *DefaultHostAPI) CustomFieldsQuery(ctx context.Context, entityType string, filters []CustomFieldFilter) ([]int64, error)

CustomFieldsQuery finds entities by custom field values.

func (*DefaultHostAPI) CustomFieldsSet

func (h *DefaultHostAPI) CustomFieldsSet(ctx context.Context, entityType string, objectID int64, values map[string]any) error

CustomFieldsSet stores custom field values for an entity.

func (*DefaultHostAPI) DBExec

func (h *DefaultHostAPI) DBExec(ctx context.Context, query string, args ...any) (int64, error)

DBExec executes a statement and returns affected rows.

func (*DefaultHostAPI) DBQuery

func (h *DefaultHostAPI) DBQuery(ctx context.Context, query string, args ...any) ([]map[string]any, error)

DBQuery executes a query and returns rows as maps.

func (*DefaultHostAPI) DeleteFile

func (h *DefaultHostAPI) DeleteFile(ctx context.Context, key string) error

DeleteFile is not available in default host.

func (*DefaultHostAPI) EntityHardDelete

func (h *DefaultHostAPI) EntityHardDelete(ctx context.Context, entityType string, entityID int64, reason string) error

EntityHardDelete is not available in default host.

func (*DefaultHostAPI) EntityRestore

func (h *DefaultHostAPI) EntityRestore(ctx context.Context, entityType string, entityID int64) error

EntityRestore is not available in default host.

func (*DefaultHostAPI) EntitySoftDelete

func (h *DefaultHostAPI) EntitySoftDelete(ctx context.Context, entityType string, entityID int64, reason string) error

EntitySoftDelete is not available in default host.

func (*DefaultHostAPI) GenerateThumbnail

func (m *DefaultHostAPI) GenerateThumbnail(_ context.Context, _ []byte, _ string, _, _ int) ([]byte, string, error)

func (*DefaultHostAPI) GetFile

func (h *DefaultHostAPI) GetFile(ctx context.Context, key string) ([]byte, map[string]string, error)

GetFile is not available in default host.

func (*DefaultHostAPI) HTTPRequest

func (h *DefaultHostAPI) HTTPRequest(ctx context.Context, method, url string, headers map[string]string, body []byte) (int, []byte, error)

HTTPRequest makes an outbound HTTP request.

func (*DefaultHostAPI) ListFiles

func (h *DefaultHostAPI) ListFiles(ctx context.Context, prefix string) ([]FileInfo, error)

ListFiles is not available in default host.

func (*DefaultHostAPI) Log

func (h *DefaultHostAPI) Log(ctx context.Context, level, message string, fields map[string]any)

Log writes a log entry.

func (*DefaultHostAPI) OrgID

func (h *DefaultHostAPI) OrgID(ctx context.Context) int64

OrgID returns 0 (no org context in default host).

func (*DefaultHostAPI) PublishEvent

func (h *DefaultHostAPI) PublishEvent(ctx context.Context, channel string, eventType string, data string) error

PublishEvent sends an SSE event to a named channel for connected browser clients.

func (*DefaultHostAPI) RecycleBinList

func (h *DefaultHostAPI) RecycleBinList(ctx context.Context, entityType string) (json.RawMessage, error)

RecycleBinList is not available in default host.

func (*DefaultHostAPI) SecureConfigGet

func (h *DefaultHostAPI) SecureConfigGet(ctx context.Context, key string) (string, error)

SecureConfigGet returns empty (not available in default host).

func (*DefaultHostAPI) SecureConfigSet

func (h *DefaultHostAPI) SecureConfigSet(ctx context.Context, key string, value string) error

SecureConfigSet returns error (not available in default host).

func (*DefaultHostAPI) SendEmail

func (h *DefaultHostAPI) SendEmail(ctx context.Context, to, subject, body string, html bool) error

SendEmail sends an email.

func (*DefaultHostAPI) StoreFile

func (h *DefaultHostAPI) StoreFile(ctx context.Context, key string, data []byte, metadata map[string]string) error

StoreFile is not available in default host.

func (*DefaultHostAPI) Translate

func (h *DefaultHostAPI) Translate(ctx context.Context, key string, args ...any) string

Translate translates a key to the current locale.

type ErrorCodeSpec

type ErrorCodeSpec = pkgplugin.ErrorCodeSpec

type FileInfo

type FileInfo = pkgplugin.FileInfo

type FileStorageBackend

type FileStorageBackend interface {
	Store(path string, data []byte, metadata map[string]string) error
	Get(path string) ([]byte, map[string]string, error)
	Delete(path string) error
	List(prefix string) ([]pkgplugin.FileInfo, error)
	Usage(prefix string) (int64, error) // total bytes under prefix
}

FileStorageBackend defines the interface for pluggable storage backends.

type GKRegistration

type GKRegistration = pkgplugin.GKRegistration

type HostAPI

type HostAPI = pkgplugin.HostAPI

type I18nSpec

type I18nSpec = pkgplugin.I18nSpec

type JobSpec

type JobSpec = pkgplugin.JobSpec

type LazyLoader

type LazyLoader interface {
	EnsureLoaded(ctx context.Context, name string) error
	Discovered() []string
	Forget(name string)
}

LazyLoader is the interface for lazy-loading plugins on demand.

type LogBuffer

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

LogBuffer is a ring buffer for plugin logs.

func GetLogBuffer

func GetLogBuffer() *LogBuffer

GetLogBuffer returns the global plugin log buffer.

func NewLogBuffer

func NewLogBuffer(maxSize int) *LogBuffer

NewLogBuffer creates a new log buffer with the given max size.

func (*LogBuffer) Add

func (b *LogBuffer) Add(entry LogEntry)

Add adds a log entry to the buffer.

func (*LogBuffer) Clear

func (b *LogBuffer) Clear()

Clear removes all entries from the buffer.

func (*LogBuffer) Count

func (b *LogBuffer) Count() int

Count returns the number of entries in the buffer.

func (*LogBuffer) GetAll

func (b *LogBuffer) GetAll() []LogEntry

GetAll returns all log entries, newest first.

func (*LogBuffer) GetByLevel

func (b *LogBuffer) GetByLevel(minLevel string) []LogEntry

GetByLevel returns log entries at or above the given level, newest first.

func (*LogBuffer) GetByPlugin

func (b *LogBuffer) GetByPlugin(pluginName string) []LogEntry

GetByPlugin returns log entries for a specific plugin, newest first.

func (*LogBuffer) GetRecent

func (b *LogBuffer) GetRecent(n int) []LogEntry

GetRecent returns the most recent n entries, newest first.

func (*LogBuffer) Log

func (b *LogBuffer) Log(plugin, level, message string, fields map[string]any)

Log adds a log entry with the given parameters.

type LogEntry

type LogEntry struct {
	Timestamp time.Time      `json:"timestamp"`
	Plugin    string         `json:"plugin"`
	Level     string         `json:"level"` // debug, info, warn, error
	Message   string         `json:"message"`
	Fields    map[string]any `json:"fields,omitempty"`
}

LogEntry represents a single plugin log entry.

type MCPToolSpec

type MCPToolSpec = pkgplugin.MCPToolSpec

type Manager

type Manager struct {

	// OnPluginLoaded is called after a plugin is lazy-loaded successfully.
	// The API layer sets this to refresh MCP tools, rebuild dynamic engine, etc.
	OnPluginLoaded func()
	// contains filtered or unexported fields
}

Manager handles plugin lifecycle: loading, registration, and invocation.

func NewManager

func NewManager(host HostAPI) *Manager

NewManager creates a plugin manager with the given host API.

func (*Manager) AllHealthStatuses

func (m *Manager) AllHealthStatuses() map[string]PluginHealth

AllHealthStatuses returns a name→health map snapshot for every registered plugin, suitable for rendering a dashboard widget or responding to an admin API call.

func (*Manager) AllPluginStats

func (m *Manager) AllPluginStats() []StatsSnapshot

AllPluginStats returns resource usage stats for all plugins.

func (*Manager) AllPolicies

func (m *Manager) AllPolicies() map[string]ResourcePolicy

AllPolicies returns all current policies.

func (*Manager) AllWidgets

func (m *Manager) AllWidgets(location string) []PluginWidget

AllWidgets returns widgets from all plugins (including lazy-loaded) for a location. This triggers lazy loading for all discovered plugins to ensure complete widget list.

func (*Manager) Call

func (m *Manager) Call(ctx context.Context, pluginName, fn string, args []byte) ([]byte, error)

Call invokes a function on a specific plugin. If lazy loading is enabled and the plugin isn't loaded yet, it will be loaded first.

func (*Manager) CallFrom

func (m *Manager) CallFrom(ctx context.Context, callerPlugin, targetPlugin, fn string, args []byte) ([]byte, error)

CallFrom invokes a function on a plugin, with caller context for better errors. If lazy loading is enabled and the plugin isn't loaded yet, it will be loaded first.

func (*Manager) Disable

func (m *Manager) Disable(name string) error

Disable disables a plugin without unloading it.

func (*Manager) Discovered

func (m *Manager) Discovered() []string

Discovered returns the names of discovered but not necessarily loaded plugins.

func (*Manager) Enable

func (m *Manager) Enable(name string) error

Enable enables a previously disabled plugin. If the plugin is lazy-loaded and not yet registered, it will be loaded first.

func (*Manager) Forget

func (m *Manager) Forget(name string)

Forget tells the lazy loader to forget a plugin so it no longer appears in Discovered().

func (*Manager) Get

func (m *Manager) Get(name string) (Plugin, bool)

Get returns a plugin by name.

func (*Manager) GetPolicy

func (m *Manager) GetPolicy(name string) (ResourcePolicy, bool)

GetPolicy returns the current policy for a plugin.

func (*Manager) HealthStatus

func (m *Manager) HealthStatus(name string) (PluginHealth, bool)

HealthStatus returns the current health snapshot for a named plugin. Returns (zero, false) if the plugin isn't registered; otherwise returns the most recent probe result.

func (*Manager) HiddenMenuItems

func (m *Manager) HiddenMenuItems() []string

HiddenMenuItems returns all menu item IDs that enabled plugins want hidden.

func (*Manager) Host

func (m *Manager) Host() HostAPI

Host returns the manager's HostAPI instance.

func (*Manager) InstalledPluginNames

func (m *Manager) InstalledPluginNames() []string

InstalledPluginNames lists the names of every enabled plugin that has completed registration. Used by the admin UI to populate the captive-plugin dropdown.

func (*Manager) IsEnabled

func (m *Manager) IsEnabled(name string) bool

IsEnabled returns whether a plugin is enabled.

func (*Manager) Jobs

func (m *Manager) Jobs() []PluginJob

Jobs returns all jobs from all enabled plugins.

func (*Manager) LandingPage

func (m *Manager) LandingPage() string

LandingPage returns the landing page URL from the first enabled plugin that declares one. If no plugin sets a landing page, returns empty string.

func (*Manager) LandingPageFor

func (m *Manager) LandingPageFor(name string) string

LandingPageFor returns the declared LandingPage for a specific enabled plugin, or empty string if the plugin isn't loaded or didn't declare one. Used by the captive-portal feature to know where to redirect a customer whose org is captive to that plugin.

func (*Manager) List

func (m *Manager) List() []GKRegistration

List returns all registered plugin manifests.

func (*Manager) MenuItems

func (m *Manager) MenuItems(location string) []PluginMenuItem

MenuItems returns all menu items from all enabled plugins.

func (*Manager) PluginStats

func (m *Manager) PluginStats(name string) (StatsSnapshot, bool)

PluginStats returns resource usage stats for a plugin.

func (*Manager) PolicyFor

func (m *Manager) PolicyFor(name string) *ResourcePolicy

PolicyFor returns the policy for a plugin, or nil if not found.

func (*Manager) Register

func (m *Manager) Register(ctx context.Context, p Plugin) error

Register loads and initializes a plugin.

func (*Manager) ReplacePlugin

func (m *Manager) ReplacePlugin(ctx context.Context, oldName string, newPlugin Plugin) error

ReplacePlugin atomically replaces an existing plugin with a new one. This prevents race conditions during hot reload.

func (*Manager) ResetCrashLoop

func (m *Manager) ResetCrashLoop(name string) bool

ResetCrashLoop clears the crash-loop-abandoned flag and restart history for a plugin. Called by the admin UI's "Retry" / "Reset" button, or after the operator has fixed the underlying problem. Returns false if the plugin isn't registered.

func (*Manager) Routes

func (m *Manager) Routes() []PluginRoute

Routes returns all routes from all enabled plugins.

func (*Manager) Scheduler

func (m *Manager) Scheduler() PlatformScheduler

Scheduler returns the platform scheduler, or nil if not set.

func (*Manager) SetLazyLoader

func (m *Manager) SetLazyLoader(loader LazyLoader)

SetLazyLoader sets the lazy loader for on-demand plugin loading.

func (*Manager) SetPolicy

func (m *Manager) SetPolicy(name string, policy ResourcePolicy)

SetPolicy sets the resource policy for a plugin (admin override). Policy changes take effect immediately and are persisted to the database.

func (*Manager) SetRestarter

func (m *Manager) SetRestarter(r Restarter)

SetRestarter wires in the loader so the health checker can attempt auto-recovery on health failures. Safe to call any time; without it, the checker only observes and logs.

func (*Manager) SetScheduler

func (m *Manager) SetScheduler(sched PlatformScheduler)

SetScheduler sets the platform scheduler for plugin job registration.

func (*Manager) ShutdownAll

func (m *Manager) ShutdownAll(ctx context.Context) error

ShutdownAll shuts down all plugins in parallel, applying a per-plugin timeout derived from the plugin's ResourcePolicy.ShutdownTimeout. A plugin that doesn't honour its own deadline is force-killed by the underlying supervisor (GRPCPlugin.Shutdown falls through to Kill()).

The outer ctx still matters: if the caller imposes a shorter deadline, every per-plugin timeout is additionally clamped by the outer context. This lets goatflow guarantee a hard ceiling on total shutdown time (e.g. 30s for the whole process) regardless of how many plugins are registered.

Plugins are shut down concurrently so the worst-case total is the max per-plugin timeout, not the sum. With N plugins each at 10s the old serial path took 10N seconds; the parallel path takes ~10s.

func (*Manager) SkipsOrgInjection

func (m *Manager) SkipsOrgInjection(name string) bool

SkipsOrgInjection returns true if the named plugin has opted out of automatic _org_id parameter injection.

func (*Manager) StartHealthChecker

func (m *Manager) StartHealthChecker(interval, probeTimeout time.Duration) func()

StartHealthChecker launches a background goroutine that periodically probes every loaded plugin and updates its health state. Returns a stop function that callers should defer at the end of the program lifetime to tear the checker down cleanly.

Passing a zero interval or probeTimeout uses the package defaults (60s / 5s). The checker is safe to start at most once per manager — subsequent calls return a no-op stop function. This mirrors how OnPluginLoaded and other manager-level hooks are wired up, where the cmd/goats/main.go startup owns the lifecycle.

If a Restarter has been wired in via SetRestarter, the checker also drives auto-recovery: unhealthy plugins are scheduled for restart with exponential backoff, and a crash-loop guard suppresses repeated restarts for plugins that won't stabilise. Without a Restarter the checker is purely observational — it logs and exposes status but never restarts anything.

func (*Manager) Unload

func (m *Manager) Unload(name string)

Unload removes a plugin from the manager's in-memory state. The plugin directory is removed by HandlePluginUnfull; this clears the registry, sandbox, and policy entries so the plugin is fully uninstalled without requiring a restart.

func (*Manager) Unregister

func (m *Manager) Unregister(ctx context.Context, name string) error

Unregister shuts down and removes a plugin.

func (*Manager) Widgets

func (m *Manager) Widgets(location string) []PluginWidget

Widgets returns all widgets from all enabled plugins for a location.

type MenuItemSpec = pkgplugin.MenuItemSpec

type Permission

type Permission = pkgplugin.Permission

type PlatformScheduledJob

type PlatformScheduledJob struct {
	Slug           string
	Handler        string
	Name           string
	Schedule       string
	TimeoutSeconds int
}

PlatformScheduledJob is the platform-level representation of a scheduled job. It contains only the fields needed by the plugin runtime, not the full product model.

type PlatformScheduler

type PlatformScheduler interface {
	AddJob(job *PlatformScheduledJob) error
	RegisterHandler(name string, handler func(ctx context.Context, job *PlatformScheduledJob) error)
}

PlatformScheduler is the interface that the plugin runtime uses to register jobs with the scheduler. The product layer provides an adapter that translates these calls into the product's scheduler.Service.

type Plugin

type Plugin = pkgplugin.Plugin

type PluginCaller

type PluginCaller struct {
	Manager    *Manager
	PluginName string
	Ctx        context.Context // Optional context for i18n
}

PluginCaller wraps plugin function calls for templates. Exported so it can be used directly in template contexts.

func (*PluginCaller) Call

func (pc *PluginCaller) Call(fn string, args ...interface{}) interface{}

Call invokes a plugin function. Used via {{ plugin.Call("fn", args) }}

func (*PluginCaller) Translate

func (pc *PluginCaller) Translate(key string, args ...interface{}) string

Translate calls the plugin's translation with the current context language.

func (*PluginCaller) Widget

func (pc *PluginCaller) Widget(widgetID string) string

Widget renders a plugin widget by ID. Returns HTML string.

type PluginDisabledError

type PluginDisabledError struct {
	PluginName   string
	CallerPlugin string
}

PluginDisabledError is returned when trying to call a disabled plugin.

func (*PluginDisabledError) Error

func (e *PluginDisabledError) Error() string

type PluginHealth

type PluginHealth struct {
	Healthy             bool      `json:"healthy"`
	LastCheck           time.Time `json:"last_check"`
	LastSuccess         time.Time `json:"last_success,omitempty"`
	ConsecutiveFailures int       `json:"consecutive_failures"`
	LastError           string    `json:"last_error,omitempty"`

	// Payload is the most recent JSON body returned by the plugin's
	// __health_ping__ handler, or nil if the plugin returned a
	// non-JSON / empty body. Plugins that want to surface custom
	// health detail (queue depth, downstream connectivity, version
	// info) should return a JSON object from their ping handler.
	Payload json.RawMessage `json:"payload,omitempty"`

	// Restart bookkeeping (for auto-recovery). All optional — only
	// meaningful when StartAutoRecovery has been wired in.
	RestartAttempts    int       `json:"restart_attempts,omitempty"`
	LastRestartAt      time.Time `json:"last_restart_at,omitempty"`
	NextRestartAt      time.Time `json:"next_restart_at,omitempty"`
	CrashLoopAbandoned bool      `json:"crash_loop_abandoned,omitempty"`
}

PluginHealth is a snapshot of a plugin's current health state. Exposed via Manager.HealthStatus for admin UIs / dashboards.

type PluginJob

type PluginJob struct {
	PluginName string
	JobSpec
}

PluginJob pairs a job spec with its plugin name.

type PluginMenuItem

type PluginMenuItem struct {
	PluginName string
	MenuItemSpec
}

PluginMenuItem pairs a menu item spec with its plugin name.

type PluginNotFoundError

type PluginNotFoundError struct {
	PluginName   string // The missing plugin
	CallerPlugin string // The plugin that tried to call it (if known)
	Function     string // The function that was called
}

PluginNotFoundError is returned when a plugin dependency is missing.

func (*PluginNotFoundError) Error

func (e *PluginNotFoundError) Error() string

type PluginRoute

type PluginRoute struct {
	PluginName string
	RouteSpec  RouteSpec
}

PluginRoute pairs a route spec with its plugin name.

type PluginStats

type PluginStats struct {
	DBQueries    atomic.Int64
	DBExecs      atomic.Int64
	CacheOps     atomic.Int64
	HTTPRequests atomic.Int64
	Calls        atomic.Int64
	Errors       atomic.Int64
	LastCallAt   atomic.Int64 // unix millis
}

PluginStats tracks resource usage for a plugin.

func (*PluginStats) Snapshot

func (s *PluginStats) Snapshot(name string) StatsSnapshot

Snapshot returns a copy of the current stats.

type PluginWidget

type PluginWidget struct {
	PluginName string
	WidgetSpec
}

PluginWidget pairs a widget spec with its plugin name.

type ProdHostAPI

type ProdHostAPI struct {
	PluginManager *Manager   // For plugin-to-plugin calls
	SSEBroker     *SSEBroker // For publishing SSE events to browsers
	// contains filtered or unexported fields
}

ProdHostAPI is the production implementation of HostAPI. It wires plugins to real database, cache, email, and other services.

func NewProdHostAPI

func NewProdHostAPI(opts ...ProdHostAPIOption) *ProdHostAPI

NewProdHostAPI creates a production host API with the given options.

func (*ProdHostAPI) CacheDelete

func (h *ProdHostAPI) CacheDelete(ctx context.Context, key string) error

CacheDelete removes a value from cache.

func (*ProdHostAPI) CacheGet

func (h *ProdHostAPI) CacheGet(ctx context.Context, key string) ([]byte, bool, error)

CacheGet retrieves a value from cache.

func (*ProdHostAPI) CacheSet

func (h *ProdHostAPI) CacheSet(ctx context.Context, key string, value []byte, ttlSeconds int) error

CacheSet stores a value in cache.

func (*ProdHostAPI) CallPlugin

func (h *ProdHostAPI) CallPlugin(ctx context.Context, pluginName, fn string, args json.RawMessage) (json.RawMessage, error)

CallPlugin calls a function in another plugin. This enables plugin-to-plugin communication via the host. If PluginCallerKey is set in the context, provides better error messages.

func (*ProdHostAPI) ConfigGet

func (h *ProdHostAPI) ConfigGet(ctx context.Context, key string) (string, error)

ConfigGet retrieves a configuration value by key path. Supports dot notation for nested values (e.g., "app.name").

func (*ProdHostAPI) CustomFieldsGet

func (h *ProdHostAPI) CustomFieldsGet(ctx context.Context, entityType string, objectID int64, fields []string) (map[string]any, error)

CustomFieldsGet retrieves custom field values for an entity.

func (*ProdHostAPI) CustomFieldsQuery

func (h *ProdHostAPI) CustomFieldsQuery(ctx context.Context, entityType string, filters []CustomFieldFilter) ([]int64, error)

CustomFieldsQuery finds entities by custom field values.

func (*ProdHostAPI) CustomFieldsSet

func (h *ProdHostAPI) CustomFieldsSet(ctx context.Context, entityType string, objectID int64, values map[string]any) error

CustomFieldsSet stores custom field values for an entity.

func (*ProdHostAPI) DBExec

func (h *ProdHostAPI) DBExec(ctx context.Context, query string, args ...any) (int64, error)

DBExec executes an INSERT/UPDATE/DELETE and returns affected rows. Uses the default database. For named databases, prefix query with "@dbname:" (e.g., "@analytics:INSERT...").

func (*ProdHostAPI) DBQuery

func (h *ProdHostAPI) DBQuery(ctx context.Context, query string, args ...any) ([]map[string]any, error)

DBQuery executes a SELECT query and returns rows as maps. Uses the default database. For named databases, prefix query with "@dbname:" (e.g., "@analytics:SELECT...").

func (*ProdHostAPI) DeleteFile

func (h *ProdHostAPI) DeleteFile(ctx context.Context, key string) error

func (*ProdHostAPI) EntityHardDelete

func (h *ProdHostAPI) EntityHardDelete(ctx context.Context, entityType string, entityID int64, reason string) error

EntityHardDelete permanently removes an entity.

func (*ProdHostAPI) EntityRestore

func (h *ProdHostAPI) EntityRestore(ctx context.Context, entityType string, entityID int64) error

EntityRestore restores a soft-deleted entity.

func (*ProdHostAPI) EntitySoftDelete

func (h *ProdHostAPI) EntitySoftDelete(ctx context.Context, entityType string, entityID int64, reason string) error

EntitySoftDelete soft-deletes an entity.

func (*ProdHostAPI) GenerateThumbnail

func (h *ProdHostAPI) GenerateThumbnail(ctx context.Context, data []byte, contentType string, maxWidth, maxHeight int) ([]byte, string, error)

GenerateThumbnail generates a thumbnail from image data using the platform's ThumbnailService (libvips via govips). For non-image types, returns a placeholder icon. The plugin does not need libvips — the host handles all image processing.

func (*ProdHostAPI) GetFile

func (h *ProdHostAPI) GetFile(ctx context.Context, key string) ([]byte, map[string]string, error)

func (*ProdHostAPI) HTTPRequest

func (h *ProdHostAPI) HTTPRequest(ctx context.Context, method, url string, headers map[string]string, body []byte) (int, []byte, error)

HTTPRequest makes an outbound HTTP request.

func (*ProdHostAPI) ListFiles

func (h *ProdHostAPI) ListFiles(ctx context.Context, prefix string) ([]pkgplugin.FileInfo, error)

func (*ProdHostAPI) Log

func (h *ProdHostAPI) Log(ctx context.Context, level, message string, fields map[string]any)

Log writes a structured log entry.

func (*ProdHostAPI) OrgID

func (h *ProdHostAPI) OrgID(ctx context.Context) int64

OrgID returns the active organisation ID from the request context.

func (*ProdHostAPI) PublishEvent

func (h *ProdHostAPI) PublishEvent(ctx context.Context, channel string, eventType string, data string) error

PublishEvent sends an SSE event to a named channel for connected browser clients.

func (*ProdHostAPI) RecycleBinList

func (h *ProdHostAPI) RecycleBinList(ctx context.Context, entityType string) (json.RawMessage, error)

RecycleBinList lists soft-deleted entities.

func (*ProdHostAPI) SecureConfigGet

func (h *ProdHostAPI) SecureConfigGet(ctx context.Context, key string) (string, error)

SecureConfigGet retrieves and decrypts a secret value.

func (*ProdHostAPI) SecureConfigSet

func (h *ProdHostAPI) SecureConfigSet(ctx context.Context, key string, value string) error

SecureConfigSet encrypts and stores a secret value.

func (*ProdHostAPI) SendEmail

func (h *ProdHostAPI) SendEmail(ctx context.Context, to, subject, body string, html bool) error

SendEmail sends an email using the configured provider.

func (*ProdHostAPI) StoreFile

func (h *ProdHostAPI) StoreFile(ctx context.Context, key string, data []byte, metadata map[string]string) error

func (*ProdHostAPI) Translate

func (h *ProdHostAPI) Translate(ctx context.Context, key string, args ...any) string

Translate translates a key to the current locale. The language is determined from the context (set via PluginLanguageKey). If no language is set, falls back to the default language.

type ProdHostAPIOption

type ProdHostAPIOption func(*ProdHostAPI)

ProdHostAPIOption is a functional option for ProdHostAPI.

func WithCache

func WithCache(c *cache.RedisCache) ProdHostAPIOption

WithCache sets the cache client.

func WithDB

func WithDB(name string, db *sql.DB) ProdHostAPIOption

WithDB adds a named database connection. Use "default" for the primary database.

func WithDefaultDB

func WithDefaultDB(name string) ProdHostAPIOption

WithDefaultDB sets which named database is the default.

func WithLogger

func WithLogger(logger *slog.Logger) ProdHostAPIOption

WithLogger sets the logger.

func WithPluginManager

func WithPluginManager(mgr *Manager) ProdHostAPIOption

WithPluginManager sets the plugin manager for plugin-to-plugin calls.

func WithThumbnailService

func WithThumbnailService(ts ThumbnailGenerator) ProdHostAPIOption

WithThumbnailService sets the thumbnail generation service.

type ResourcePolicy

type ResourcePolicy = pkgplugin.ResourcePolicy

type ResourceRequest

type ResourceRequest = pkgplugin.ResourceRequest

type Restarter

type Restarter interface {
	Reload(ctx context.Context, name string) error
}

Restarter is the hook the manager uses to actually re-spawn a plugin process after a health failure. It's an interface so the manager doesn't depend on the loader package — the loader (which already knows how to discover and (re)spawn WASM/gRPC plugins) implements this and is wired in via SetRestarter at startup.

type RouteSpec

type RouteSpec = pkgplugin.RouteSpec

type SSEBroker

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

SSEBroker manages SSE client connections and event broadcasting.

func NewSSEBroker

func NewSSEBroker() *SSEBroker

NewSSEBroker creates a new SSE broker.

func (*SSEBroker) ClientCount

func (b *SSEBroker) ClientCount() int

ClientCount returns the number of connected SSE clients.

func (*SSEBroker) Publish

func (b *SSEBroker) Publish(event SSEEvent)

Publish sends an event to all matching clients. Non-blocking: slow clients have their events dropped rather than blocking the publisher.

func (*SSEBroker) ServeChannel

func (b *SSEBroker) ServeChannel(w http.ResponseWriter, r *http.Request, pluginName, channel string)

ServeChannel handles SSE connections scoped to a specific plugin and channel.

func (*SSEBroker) ServeHTTP

func (b *SSEBroker) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP handles SSE client connections. Query params:

  • plugin: filter events to a specific plugin (optional, for legacy /api/v1/sse)

func (*SSEBroker) Subscribe

func (b *SSEBroker) Subscribe(plugin, channel string) chan SSEEvent

Subscribe adds a client filtered by plugin and channel. Both filters are required (non-empty) for per-plugin channel isolation.

func (*SSEBroker) Unsubscribe

func (b *SSEBroker) Unsubscribe(ch chan SSEEvent)

Unsubscribe removes a client channel.

type SSEEvent

type SSEEvent struct {
	Plugin  string // source plugin name
	Channel string // channel name (e.g. "status", "progress")
	Type    string // event type (e.g. "device-table")
	Data    string // event data (typically HTML fragment)
}

SSEEvent represents a server-sent event.

type SandboxedHostAPI

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

SandboxedHostAPI wraps a HostAPI with per-plugin permission enforcement and resource accounting. Each plugin gets its own sandbox instance.

func NewSandboxedHostAPI

func NewSandboxedHostAPI(inner HostAPI, pluginName string, policy ResourcePolicy) *SandboxedHostAPI

NewSandboxedHostAPI creates a permission-enforcing wrapper around a HostAPI.

func (*SandboxedHostAPI) CacheDelete

func (s *SandboxedHostAPI) CacheDelete(ctx context.Context, key string) error

func (*SandboxedHostAPI) CacheGet

func (s *SandboxedHostAPI) CacheGet(ctx context.Context, key string) ([]byte, bool, error)

func (*SandboxedHostAPI) CacheSet

func (s *SandboxedHostAPI) CacheSet(ctx context.Context, key string, value []byte, ttlSeconds int) error

func (*SandboxedHostAPI) CallPlugin

func (s *SandboxedHostAPI) CallPlugin(ctx context.Context, pluginName, fn string, args json.RawMessage) (json.RawMessage, error)

func (*SandboxedHostAPI) ConfigGet

func (s *SandboxedHostAPI) ConfigGet(ctx context.Context, key string) (string, error)

func (*SandboxedHostAPI) CustomFieldsGet

func (s *SandboxedHostAPI) CustomFieldsGet(ctx context.Context, entityType string, objectID int64, fields []string) (map[string]any, error)

CustomFieldsGet retrieves custom field values, scoped to this plugin's prefixed fields + admin/legacy fields.

func (*SandboxedHostAPI) CustomFieldsQuery

func (s *SandboxedHostAPI) CustomFieldsQuery(ctx context.Context, entityType string, filters []CustomFieldFilter) ([]int64, error)

CustomFieldsQuery finds entities by custom field values, scoped to this plugin's fields.

func (*SandboxedHostAPI) CustomFieldsSet

func (s *SandboxedHostAPI) CustomFieldsSet(ctx context.Context, entityType string, objectID int64, values map[string]any) error

CustomFieldsSet stores custom field values, scoped to this plugin's fields.

func (*SandboxedHostAPI) DBExec

func (s *SandboxedHostAPI) DBExec(ctx context.Context, query string, args ...any) (int64, error)

func (*SandboxedHostAPI) DBQuery

func (s *SandboxedHostAPI) DBQuery(ctx context.Context, query string, args ...any) ([]map[string]any, error)

func (*SandboxedHostAPI) DeleteFile

func (s *SandboxedHostAPI) DeleteFile(ctx context.Context, key string) error

func (*SandboxedHostAPI) EntityHardDelete

func (s *SandboxedHostAPI) EntityHardDelete(ctx context.Context, entityType string, entityID int64, reason string) error

EntityHardDelete permanently removes an entity.

func (*SandboxedHostAPI) EntityRestore

func (s *SandboxedHostAPI) EntityRestore(ctx context.Context, entityType string, entityID int64) error

EntityRestore restores a soft-deleted entity.

func (*SandboxedHostAPI) EntitySoftDelete

func (s *SandboxedHostAPI) EntitySoftDelete(ctx context.Context, entityType string, entityID int64, reason string) error

EntitySoftDelete soft-deletes an entity.

func (*SandboxedHostAPI) GenerateThumbnail

func (s *SandboxedHostAPI) GenerateThumbnail(ctx context.Context, data []byte, contentType string, maxWidth, maxHeight int) ([]byte, string, error)

func (*SandboxedHostAPI) GetFile

func (s *SandboxedHostAPI) GetFile(ctx context.Context, key string) ([]byte, map[string]string, error)

func (*SandboxedHostAPI) HTTPRequest

func (s *SandboxedHostAPI) HTTPRequest(ctx context.Context, method, url string, headers map[string]string, body []byte) (int, []byte, error)

func (*SandboxedHostAPI) ListFiles

func (s *SandboxedHostAPI) ListFiles(ctx context.Context, prefix string) ([]FileInfo, error)

func (*SandboxedHostAPI) Log

func (s *SandboxedHostAPI) Log(ctx context.Context, level, message string, fields map[string]any)

func (*SandboxedHostAPI) OrgID

func (s *SandboxedHostAPI) OrgID(ctx context.Context) int64

OrgID returns the active organisation ID from the request context.

func (*SandboxedHostAPI) PublishEvent

func (s *SandboxedHostAPI) PublishEvent(ctx context.Context, channel string, eventType string, data string) error

PublishEvent sends an SSE event to a named channel for connected browser clients. The plugin name is automatically set from the sandbox context.

func (*SandboxedHostAPI) RecycleBinList

func (s *SandboxedHostAPI) RecycleBinList(ctx context.Context, entityType string) (json.RawMessage, error)

RecycleBinList lists soft-deleted entities.

func (*SandboxedHostAPI) SecureConfigGet

func (s *SandboxedHostAPI) SecureConfigGet(ctx context.Context, key string) (string, error)

SecureConfigGet retrieves a decrypted secret, scoped to this plugin.

func (*SandboxedHostAPI) SecureConfigSet

func (s *SandboxedHostAPI) SecureConfigSet(ctx context.Context, key string, value string) error

SecureConfigSet stores an encrypted secret, scoped to this plugin.

func (*SandboxedHostAPI) SendEmail

func (s *SandboxedHostAPI) SendEmail(ctx context.Context, to, subject, body string, html bool) error

func (*SandboxedHostAPI) Stats

func (s *SandboxedHostAPI) Stats() StatsSnapshot

Stats returns the resource accounting stats for this plugin.

func (*SandboxedHostAPI) StoreFile

func (s *SandboxedHostAPI) StoreFile(ctx context.Context, key string, data []byte, metadata map[string]string) error

func (*SandboxedHostAPI) Translate

func (s *SandboxedHostAPI) Translate(ctx context.Context, key string, args ...any) string

func (*SandboxedHostAPI) UpdatePolicy

func (s *SandboxedHostAPI) UpdatePolicy(policy ResourcePolicy)

UpdatePolicy updates the resource policy for this sandbox. Policy changes take effect immediately for new requests.

type StatsSnapshot

type StatsSnapshot struct {
	PluginName   string `json:"plugin_name"`
	DBQueries    int64  `json:"db_queries"`
	DBExecs      int64  `json:"db_execs"`
	CacheOps     int64  `json:"cache_ops"`
	HTTPRequests int64  `json:"http_requests"`
	Calls        int64  `json:"calls"`
	Errors       int64  `json:"errors"`
	LastCallAt   int64  `json:"last_call_at"`
}

StatsSnapshot returns a point-in-time copy of plugin stats.

type TemplateOverride

type TemplateOverride struct {
	PluginName   string // Plugin providing the override
	TemplateName string // Original template name being overridden
	Handler      string // Plugin function to call for template content
}

TemplateOverride stores information about a template override.

type TemplateOverrideRegistry

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

TemplateOverrideRegistry manages template overrides from plugins.

func GetTemplateOverrides

func GetTemplateOverrides() *TemplateOverrideRegistry

GetTemplateOverrides returns the global template override registry.

func NewTemplateOverrideRegistry

func NewTemplateOverrideRegistry(mgr *Manager) *TemplateOverrideRegistry

NewTemplateOverrideRegistry creates a new template override registry.

func (*TemplateOverrideRegistry) GetOverride

func (r *TemplateOverrideRegistry) GetOverride(templateName string) *TemplateOverride

GetOverride returns the override for a template, if any.

func (*TemplateOverrideRegistry) HasOverride

func (r *TemplateOverrideRegistry) HasOverride(templateName string) bool

HasOverride checks if a template has a plugin override.

func (*TemplateOverrideRegistry) List

List returns all registered overrides.

func (*TemplateOverrideRegistry) Register

func (r *TemplateOverrideRegistry) Register(pluginName string, templates []TemplateSpec)

Register registers template overrides from a plugin.

func (*TemplateOverrideRegistry) RenderOverride

func (r *TemplateOverrideRegistry) RenderOverride(ctx context.Context, templateName string, data map[string]any) (string, bool)

RenderOverride renders a template override by calling the plugin. Returns the rendered HTML and true if an override exists, empty string and false otherwise.

func (*TemplateOverrideRegistry) Unregister

func (r *TemplateOverrideRegistry) Unregister(pluginName string)

Unregister removes template overrides for a plugin.

type TemplateSpec

type TemplateSpec = pkgplugin.TemplateSpec

type ThumbnailGenerator

type ThumbnailGenerator interface {
	GenerateThumbnail(data []byte, contentType string, maxWidth, maxHeight int) ([]byte, string, error)
}

ThumbnailGenerator generates thumbnails from image data. Implemented by service.ThumbnailService (via an adapter) so the platform layer doesn't import internal/service directly.

func NewThumbnailGenerator

func NewThumbnailGenerator(fn func(data []byte, contentType string, maxWidth, maxHeight int) ([]byte, string, error)) ThumbnailGenerator

NewThumbnailGenerator creates a ThumbnailGenerator from a function. This lets main.go pass a closure that calls service.ThumbnailService without this package importing internal/service.

type ThumbnailServiceAdapter

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

thumbnailServiceAdapter wraps service.ThumbnailService to satisfy ThumbnailGenerator. Defined here so the platform layer stays decoupled; the adapter is constructed in main.go where service is imported.

func (*ThumbnailServiceAdapter) GenerateThumbnail

func (a *ThumbnailServiceAdapter) GenerateThumbnail(data []byte, contentType string, maxWidth, maxHeight int) ([]byte, string, error)

type UIAuthSpec

type UIAuthSpec = pkgplugin.UIAuthSpec

type UIBrandingSpec

type UIBrandingSpec = pkgplugin.UIBrandingSpec

type UINavItem

type UINavItem = pkgplugin.UINavItem

type UINavSpec

type UINavSpec = pkgplugin.UINavSpec

type UIPWASpec

type UIPWASpec = pkgplugin.UIPWASpec

type UIRouteSpec

type UIRouteSpec = pkgplugin.UIRouteSpec

type UISpec

type UISpec = pkgplugin.UISpec

type WidgetSpec

type WidgetSpec = pkgplugin.WidgetSpec

Directories

Path Synopsis
Package core provides core built-in plugins for GoatFlow.
Package core provides core built-in plugins for GoatFlow.
Package example provides example plugin implementations for testing.
Package example provides example plugin implementations for testing.
Package grpc provides gRPC-based plugin runtime using HashiCorp go-plugin.
Package grpc provides gRPC-based plugin runtime using HashiCorp go-plugin.
example command
Example gRPC plugin for GoatKit.
Example gRPC plugin for GoatKit.
Package packaging provides ZIP-based plugin packaging and extraction.
Package packaging provides ZIP-based plugin packaging and extraction.
Package wasm provides a WASM-based plugin runtime using wazero.
Package wasm provides a WASM-based plugin runtime using wazero.

Jump to

Keyboard shortcuts

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