Documentation
¶
Overview ¶
Package extensions loads, verifies and runs Ammonode extensions: a signed zip package (.ammx) with a manifest, an optional WebAssembly backend run by Extism, and an optional browser module that fills UI slots.
Index ¶
- Constants
- Variables
- func Digest(files map[string][]byte) []byte
- func Satisfies(v Version, rng string) (bool, error)
- func Scaffold(dir, id, name string) error
- func WritePackage(files map[string][]byte, key ed25519.PrivateKey) ([]byte, error)
- type CheckoutInput
- type CheckoutOutput
- type Customer
- type Gateway
- type HTTPRequest
- type HTTPResponse
- type Host
- type HostOptions
- type InvoiceInfo
- type KV
- type Manifest
- type Package
- type Permissions
- type ProvisionInput
- type ProvisionOutput
- type ProvisionProduct
- type ProvisionSubscription
- type ProvisionUser
- type Provisioner
- type Setting
- type Version
- type WebhookInput
- type WebhookOutput
Constants ¶
const ( FnOnEvent = "on_event" // input {event, data} FnGatewayCheckout = "gateway_checkout" // input CheckoutInput, output CheckoutOutput FnGatewayWebhook = "gateway_webhook" // input WebhookInput, output WebhookOutput // Provisioners: input ProvisionInput; create returns ProvisionOutput, the others nothing. FnProvisionCreate = "provision_create" FnProvisionSuspend = "provision_suspend" FnProvisionUnsuspend = "provision_unsuspend" FnProvisionTerminate = "provision_terminate" FnProvisionChange = "provision_change" // new memory/CPU/disk )
Exported functions the core calls when a plugin has them.
const APIVersion = "1.0.0"
APIVersion is the extension API the core offers. Bump the minor version for additions and the major version for breaking changes (extensions declare a range in "api").
Variables ¶
var ErrNotLoaded = errors.New("extension not loaded")
ErrNotLoaded means the extension is not running (disabled, or without a backend).
var Events = []string{
"user.registered", "invoice.created", "invoice.paid",
"service.provisioned", "subscription.suspended", "subscription.ended",
}
Events the core emits (permissions.events must be a subset).
Functions ¶
func Digest ¶
Digest is a stable hash of the package content: sha256 over "name\nsha256hex\n" lines sorted by name. Zip metadata (dates, order, compression) does not matter.
func Satisfies ¶
Satisfies reports whether v matches a range: "^1.2" (same major, ≥ 1.2.0; for 0.x the same minor), "~1.2" (same minor), "1.x" / "1.2.x", ">=1.0 <2.0" (space-separated comparators, all must hold), "*", or an exact version.
func WritePackage ¶
WritePackage zips files (name → content), signing them when key is set.
Types ¶
type CheckoutInput ¶
type CheckoutInput struct {
Invoice InvoiceInfo `json:"invoice"`
Customer Customer `json:"customer"`
ReturnURL string `json:"return_url"`
CancelURL string `json:"cancel_url"`
WebhookURL string `json:"webhook_url"`
}
CheckoutInput is sent to gateway_checkout.
type CheckoutOutput ¶
type CheckoutOutput struct {
RedirectURL string `json:"redirect_url"`
}
CheckoutOutput is where to send the customer.
type Gateway ¶
type Gateway struct {
Name string `json:"name"` // shown on the pay button
Currencies []string `json:"currencies"` // empty = any
}
Gateway describes a payment gateway extension.
func (*Gateway) SupportsCurrency ¶
SupportsCurrency reports whether a gateway extension takes the currency.
type HTTPRequest ¶
type HTTPRequest struct {
Method string `json:"method"`
URL string `json:"url"`
Headers map[string]string `json:"headers,omitempty"`
Body string `json:"body,omitempty"`
}
HTTPRequest is the input of the http_request host function.
type HTTPResponse ¶
type HTTPResponse struct {
Status int `json:"status"`
Headers map[string]string `json:"headers,omitempty"`
Body string `json:"body"`
Error string `json:"error,omitempty"`
}
HTTPResponse is its output; Error is set when the request was not made or failed.
type Host ¶
type Host struct {
// contains filtered or unexported fields
}
Host keeps compiled plugins and calls them.
func NewHost ¶
func NewHost(opts HostOptions) *Host
NewHost creates the runtime. Plugins make HTTP requests through the http_request host function (Extism's built-in HTTP is switched off: it uses http.DefaultClient, which cannot be restricted per plugin); its client refuses private and loopback addresses, so an allowed host name cannot be pointed at the panel's own network.
func (*Host) Call ¶
Call runs fn with JSON input and decodes the JSON output into out (when not nil). Each call gets a fresh instance, so plugins keep no memory between calls (use kv for that).
type HostOptions ¶
type HostOptions struct {
Logger *slog.Logger
KV KV
// AllowPrivateNetworks lets plugin HTTP reach private/loopback addresses (tests only).
AllowPrivateNetworks bool
}
HostOptions configure the runtime.
type InvoiceInfo ¶
type InvoiceInfo struct {
ID string `json:"id"`
Number string `json:"number"`
Total int64 `json:"total"`
Currency string `json:"currency"`
}
InvoiceInfo describes the invoice to pay. Amounts are in the smallest currency unit.
type KV ¶
type KV interface {
Get(ctx context.Context, ext, key string) ([]byte, bool, error)
Set(ctx context.Context, ext, key string, value []byte) error
}
KV is per-extension storage behind the kv_get / kv_set host functions.
type Manifest ¶
type Manifest struct {
ID string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
API string `json:"api"` // semver range of the core API, e.g. "^1.0"
Description string `json:"description,omitempty"`
Author string `json:"author,omitempty"`
Homepage string `json:"homepage,omitempty"`
Backend string `json:"backend,omitempty"` // path of the .wasm in the package
Frontend string `json:"frontend,omitempty"` // path of the ES module in the package
Permissions Permissions `json:"permissions"`
Settings []Setting `json:"settings,omitempty"`
Gateway *Gateway `json:"gateway,omitempty"` // set when the extension is a payment gateway
// Provisioner is set when the extension delivers products on another system (a
// Pterodactyl or Pelican panel, Proxmox, ...).
Provisioner *Provisioner `json:"provisioner,omitempty"`
}
Manifest is extension.json.
func PackDir ¶
PackDir reads an extension project and returns the files that go into its package: extension.json, the backend and frontend it names, and README.md / LICENSE if present.
func ParseManifest ¶
ParseManifest decodes and validates extension.json.
type Package ¶
type Package struct {
Manifest Manifest
Files map[string][]byte // every file except the signature
Signer string // base64 public key of a valid signature, "" if unsigned
}
Package is a read package.
func ReadPackage ¶
ReadPackage unpacks and validates a package. A present but invalid signature is an error; whether unsigned packages are acceptable is the caller's decision (Signer == "").
type Permissions ¶
type Permissions struct {
// HTTP lists hosts the plugin may call: exact, "*.example.com", or "setting:<key>" for
// the host of a URL the admin enters in that setting (e.g. a self-hosted panel).
HTTP []string `json:"http,omitempty"`
Events []string `json:"events,omitempty"` // core events delivered to on_event
KV bool `json:"kv,omitempty"` // a small key/value store
}
Permissions are what the backend may do; everything else is denied.
type ProvisionInput ¶
type ProvisionInput struct {
Subscription ProvisionSubscription `json:"subscription"`
User ProvisionUser `json:"user"`
Product ProvisionProduct `json:"product"`
// ExternalID is what provision_create returned (empty for create).
ExternalID string `json:"external_id"`
}
ProvisionInput is what a provisioner gets for every call.
type ProvisionOutput ¶
type ProvisionOutput struct {
ExternalID string `json:"external_id"`
// Info is shown to the customer: a link to manage it, and a few details.
Info struct {
URL string `json:"url,omitempty"`
Details map[string]string `json:"details,omitempty"`
} `json:"info"`
}
ProvisionOutput identifies the delivered thing on the other system.
type ProvisionProduct ¶
type ProvisionProduct struct {
ID string `json:"id"`
Name string `json:"name"`
Settings map[string]string `json:"settings"`
}
ProvisionProduct carries the product's provisioner settings.
type ProvisionSubscription ¶
type ProvisionSubscription struct {
ID string `json:"id"`
Name string `json:"name"`
Cycle string `json:"cycle"`
MemoryMB int `json:"memory_mb"`
CPUPercent int `json:"cpu_percent"`
DiskMB int `json:"disk_mb"`
}
ProvisionSubscription is the purchase being delivered.
type ProvisionUser ¶
type ProvisionUser struct {
ID string `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
}
ProvisionUser is the customer.
type Provisioner ¶
type Provisioner struct {
Name string `json:"name"`
Settings []Setting `json:"settings,omitempty"`
}
Provisioner describes a provisioner extension. Settings are per product (e.g. the egg or VM template); the extension's own settings hold the connection.
type Setting ¶
type Setting struct {
Key string `json:"key"`
Label string `json:"label"`
Type string `json:"type"` // text | secret | boolean
Required bool `json:"required,omitempty"`
Help string `json:"help,omitempty"`
}
Setting is a value the admin fills in; the backend reads it as plugin config.
type Version ¶
type Version struct{ Major, Minor, Patch int }
Version is a semantic version (pre-release and build suffixes are ignored for ordering).
func ParseVersion ¶
ParseVersion parses "1", "1.2" or "1.2.3" (a leading "v" is allowed).
type WebhookInput ¶
type WebhookInput struct {
Method string `json:"method"`
Headers map[string][]string `json:"headers"`
Query map[string][]string `json:"query"`
Body string `json:"body"`
}
WebhookInput is an HTTP request to /api/webhooks/ext/{id}.
type WebhookOutput ¶
type WebhookOutput struct {
Status string `json:"status"`
InvoiceID string `json:"invoice_id"`
Ref string `json:"ref"`
Amount int64 `json:"amount"`
Currency string `json:"currency"`
// RedirectURL continues a browser flow (GET) on a page of the panel.
RedirectURL string `json:"redirect_url,omitempty"`
}
WebhookOutput reports a payment ("paid") or nothing ("ignored").