Documentation
¶
Overview ¶
Package ext is the extension system (spec §4.9): extensions are external programs described by a manifest. Installing one validates the manifest, registers its content types and settings and issues a scoped API key; activating it subscribes its declared hooks, which the HTTP bridge delivers to the extension's endpoint as HMAC-signed JSON. There are no Go native plugins: internal modules and extensions use the same hooks registry, the bridge is just another subscriber. See docs/EXTENSIONS.md.
Index ¶
- Constants
- Variables
- func Sign(secret []byte, ts string, body []byte) string
- func Verify(secret []byte, ts string, body []byte, sig string, now time.Time, ...) error
- type ContentType
- type Delivery
- type Endpoint
- type Extension
- type HookSpec
- type InstallResult
- type Manifest
- type Module
- type NavLink
- type Service
- type SettingField
- type UninstallResponse
- type ValidationError
Constants ¶
const ( KindAction = "action" // sync hooks.Do → async delivery (job ext.deliver) KindFilter = "filter" // sync round trip; the response replaces the value KindEvent = "event" // hooks.Emit → async delivery (job ext.deliver) )
Hook kinds a manifest may subscribe with.
const ( HeaderSignature = "X-GoRun-Signature" HeaderTimestamp = "X-GoRun-Timestamp" HeaderExtension = "X-GoRun-Extension" HeaderDelivery = "X-GoRun-Delivery" )
Bridge headers.
const ( StatusInstalled = "installed" StatusActive = "active" StatusDisabled = "disabled" StatusError = "error" )
Extension statuses (spec §3).
const DeliverJobKind = "ext.deliver"
DeliverJobKind is the job that delivers actions and events to an extension endpoint (async, retried with the queue's backoff).
const (
MaxZipSize = 20 << 20 // upload cap
)
Package limits.
const Perm = "extensions.manage"
Perm is the permission for managing extensions.
const ServiceName = "ext"
ServiceName is the kernel service name of ext.Service.
Variables ¶
var ErrNoOwner = errors.New("ext: no active admin user to own the extension API key")
ErrNoOwner is returned by Install when no active admin user can own the extension's API key.
var ErrNotFound = notFoundError{}
ErrNotFound is returned for an unknown extension slug.
Functions ¶
Types ¶
type ContentType ¶
ContentType is a content type declared by an extension (content.Type shaped; System is always forced to false).
type Delivery ¶
type Delivery struct {
ID string `json:"id"`
DeliveryID string `json:"delivery_id"`
Hook string `json:"hook"`
Kind string `json:"kind"`
Status string `json:"status"` // ok | error | timeout
HTTPStatus int `json:"http_status"`
DurationMS int64 `json:"duration_ms"`
Error string `json:"error"`
CreatedAt string `json:"created_at"`
}
Delivery is one bridge attempt in the delivery log.
type Endpoint ¶
type Endpoint struct {
URL string `json:"url"`
Auth string `json:"auth"` // "hmac" (the only scheme in v1)
}
Endpoint is where the HTTP bridge delivers hooks.
type Extension ¶
type Extension struct {
Slug string `json:"slug"`
Name map[string]string `json:"name"`
Version string `json:"version"`
Status string `json:"status"`
EndpointURL string `json:"endpoint_url"`
APIKeyID string `json:"api_key_id"`
Failures int `json:"failures"`
TotalFailures int `json:"total_failures"`
InstalledAt string `json:"installed_at"`
ActivatedAt string `json:"activated_at"`
LastError string `json:"last_error"`
Manifest Manifest `json:"manifest"`
// contains filtered or unexported fields
}
Extension is an installed extension. The HMAC secret and API key plaintext are never part of it (they are shown once, at install).
func (Extension) DisplayName ¶
DisplayName returns the extension name in locale.
func (Extension) HooksCount ¶
HooksCount is the number of hook subscriptions declared.
type HookSpec ¶
type HookSpec struct {
Name string `json:"name"`
Kind string `json:"kind"` // action | filter | event
TimeoutMS int `json:"timeout_ms,omitempty"` // filters: default 2000, max 10000
}
HookSpec subscribes the extension to one hook.
type InstallResult ¶
type InstallResult struct {
Extension *Extension `json:"extension"`
APIKey string `json:"api_key"`
Secret string `json:"secret"`
}
InstallResult is returned once by Install: APIKey (empty when the manifest requests no permissions) and Secret are not stored in plaintext and cannot be shown again.
type Manifest ¶
type Manifest struct {
Slug string `json:"slug"`
Name map[string]string `json:"name"`
Version string `json:"version"`
Description map[string]string `json:"description,omitempty"`
Author string `json:"author,omitempty"`
Permissions []string `json:"permissions"`
Hooks []HookSpec `json:"hooks"`
ContentTypes []ContentType `json:"content_types,omitempty"`
Settings []SettingField `json:"settings,omitempty"`
Endpoint Endpoint `json:"endpoint"`
}
Manifest is extensions/<slug>/manifest.json (spec §4.9).
func InspectDeclarativeZip ¶
InspectDeclarativeZip reuses native package guards without installing in the catalog host.
func ParseManifest ¶
ParseManifest decodes a manifest strictly (unknown fields are errors) and normalizes defaults. It does not validate; Install does.
func (*Manifest) DisplayName ¶
DisplayName returns the name in locale, falling back to en then the slug.
type Module ¶
type Module struct{}
Module is the ext kernel.Module.
type NavLink ¶
type NavLink struct {
}
NavLink is an admin link the extension offers (shown on its admin page).
type Service ¶
type Service interface {
// InstallDir installs the package in dir (manifest.json + optional
// assets/). The package is copied to <DataDir>/extensions/<slug>/
// unless dir already is that directory.
InstallDir(ctx context.Context, dir string) (*InstallResult, error)
// InstallZip installs a zipped package (manifest.json at the root or
// inside one top-level folder), at most MaxZipSize bytes.
InstallZip(ctx context.Context, r io.ReaderAt, size int64) (*InstallResult, error)
Activate(ctx context.Context, slug string) error
Deactivate(ctx context.Context, slug string) error
// Uninstall removes the extension and revokes its API key. Declared
// content types, their content, its settings and its package directory
// are deleted only when purge is true.
Uninstall(ctx context.Context, slug string, purge bool) error
List(ctx context.Context) ([]Extension, error)
Status(ctx context.Context, slug string) (*Extension, error)
Deliveries(ctx context.Context, slug string, limit int) ([]Delivery, error)
// Available lists packages present under <DataDir>/extensions/ that are
// not installed yet.
Available(ctx context.Context) ([]Manifest, error)
}
Service manages extensions: install (from a directory or a zip), activate, deactivate, uninstall, and their delivery log.
type SettingField ¶
SettingField is a setting declared by an extension (content.Field shaped).
type UninstallResponse ¶
UninstallResponse is returned by DELETE /v1/extensions/{slug}.
type ValidationError ¶
type ValidationError struct {
Fields map[string]string `json:"fields"`
// Detail is untranslated technical detail (e.g. the JSON decode error of
// a bad manifest), shown escaped in the admin and logged.
Detail string `json:"detail,omitempty"`
}
ValidationError lists manifest or package problems keyed by field path ("hooks.0.kind") with i18n message keys.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
func (*ValidationError) FieldErrors ¶
func (e *ValidationError) FieldErrors() map[string]string
FieldErrors implements api.FieldErrorer.