Help us shape the future of Go! Take the 2026 Go Developer Survey

ext

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 18, 2026 License: AGPL-3.0 Imports: 43 Imported by: 0

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

View Source
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.

View Source
const (
	HeaderSignature = "X-GoRun-Signature"
	HeaderTimestamp = "X-GoRun-Timestamp"
	HeaderExtension = "X-GoRun-Extension"
	HeaderDelivery  = "X-GoRun-Delivery"
)

Bridge headers.

View Source
const (
	StatusInstalled = "installed"
	StatusActive    = "active"
	StatusDisabled  = "disabled"
	StatusError     = "error"
)

Extension statuses (spec §3).

View Source
const DeliverJobKind = "ext.deliver"

DeliverJobKind is the job that delivers actions and events to an extension endpoint (async, retried with the queue's backoff).

View Source
const (
	MaxZipSize = 20 << 20 // upload cap

)

Package limits.

View Source
const Perm = "extensions.manage"

Perm is the permission for managing extensions.

View Source
const ServiceName = "ext"

ServiceName is the kernel service name of ext.Service.

Variables

View Source
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.

View Source
var ErrNotFound = notFoundError{}

ErrNotFound is returned for an unknown extension slug.

Functions

func Sign

func Sign(secret []byte, ts string, body []byte) string

Sign returns hex(hmac_sha256(secret, ts + "\n" + body)): the X-GoRun-Signature of a bridge request whose X-GoRun-Timestamp is ts (unix seconds, the same value as the body's "ts").

func Verify

func Verify(secret []byte, ts string, body []byte, sig string, now time.Time, skew time.Duration) error

Verify checks a bridge signature in constant time and rejects timestamps further than skew from now (replay window).

Types

type ContentType

type ContentType = content.Type

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

func (x Extension) DisplayName(locale string) string

DisplayName returns the extension name in locale.

func (Extension) HooksCount

func (x Extension) HooksCount() int

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"`
	AdminNav     []NavLink         `json:"admin_nav,omitempty"`
	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

func InspectDeclarativeZip(r io.ReaderAt, size int64) (*Manifest, error)

InspectDeclarativeZip reuses native package guards without installing in the catalog host.

func ParseManifest

func ParseManifest(raw []byte) (*Manifest, error)

ParseManifest decodes a manifest strictly (unknown fields are errors) and normalizes defaults. It does not validate; Install does.

func (*Manifest) DisplayName

func (m *Manifest) DisplayName(locale string) string

DisplayName returns the name in locale, falling back to en then the slug.

type Module

type Module struct{}

Module is the ext kernel.Module.

func New

func New() *Module

New returns the ext module.

func (*Module) Catalogs

func (*Module) Catalogs() fs.FS

Catalogs implements kernel.CatalogProvider.

func (*Module) Migrations

func (*Module) Migrations() fs.FS

Migrations implements kernel.Module.

func (*Module) Name

func (*Module) Name() string

Name implements kernel.Module.

func (*Module) Register

func (*Module) Register(d *kernel.Deps) error

Register declares the permission, publishes the service, resubscribes active extensions, and adds the delivery job, health check, admin screens and API operations.

type NavLink struct {
	Label map[string]string `json:"label"`
	URL   string            `json:"url"`
}

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

type SettingField = content.Field

SettingField is a setting declared by an extension (content.Field shaped).

type UninstallResponse

type UninstallResponse struct {
	Slug   string `json:"slug"`
	Purged bool   `json:"purged"`
}

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.

Jump to

Keyboard shortcuts

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