plugin

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Jul 27, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AutoWorkerCount

func AutoWorkerCount() int

AutoWorkerCount returns the auto-scaled worker count: min(NumCPU/2, 8) with floor 2.

func CheckNodeAvailable

func CheckNodeAvailable() error

CheckNodeAvailable verifies that the `node` binary is available in PATH.

func CheckSandbox

func CheckSandbox(runtime interface{}) error

CheckSandbox validates that the Tier 2 runtime has no filesystem or network access. Both QuickJS and WASM runtimes are sandboxed by design — no host imports for filesystem or network are provided.

func EncodeMessage

func EncodeMessage(msg *Message) ([]byte, error)

EncodeMessage serializes a Message into an LSP-style framed byte sequence. For hook messages with large HTML/content fields, uses split-body framing: Content-Length: <N>\r\nX-Body-Length: <M>\r\nX-Body-Field: <field>\r\n\r\n<JSON><raw bytes> For all other messages, uses standard single-header framing: Content-Length: <N>\r\n\r\n<JSON body>

func ResolveWorkerCount

func ResolveWorkerCount(configured interface{}) int

ResolveWorkerCount resolves a configured worker count to a concrete integer. Positive integers are returned as-is (no floor applied). All other values (including "auto", 0, negative, or unrecognized types) fall back to AutoWorkerCount.

func ValidateScope

func ValidateScope(event HookName, scope HookScope) error

ValidateScope checks that a scope is valid for the given hook event.

Types

type BatchHookFunc

type BatchHookFunc func(ctx context.Context, payloads []interface{}, onProgress BatchProgressFunc) ([]interface{}, error)

BatchHookFunc processes multiple payloads in a single call, returning one result per input. Used by subprocess plugins to distribute work across multiple worker processes. The onProgress callback, when non-nil, is called after each item completes.

type BatchProgressFunc

type BatchProgressFunc func(completed, total int)

BatchProgressFunc is called after each item is dispatched during batch hook execution (including timed-out items), reporting the running count and total.

type BridgeState

type BridgeState int

BridgeState represents the lifecycle state of the Node subprocess bridge.

const (
	// BridgeNotStarted is the initial state before Start() is called.
	BridgeNotStarted BridgeState = iota + 1
	// BridgeRunning means the Node subprocess is active and accepting messages.
	BridgeRunning
	// BridgeStopped means the Node subprocess has been shut down.
	BridgeStopped
)

type EvalWarner

type EvalWarner interface {
	EvalWarnings() []string
}

EvalWarner is implemented by runtimes that collect warnings during plugin evaluation.

type FileChangedResult added in v0.6.0

type FileChangedResult struct {
	InvalidateByDependency []string
	Restart                bool
	Warnings               []string
}

FileChangedResult holds the structured return value from an onFileChanged hook. Nil when the plugin returns nil, non-map, or a map with no recognized keys (backward-compatible no-op).

func ParseFileChangedResult added in v0.6.0

func ParseFileChangedResult(result interface{}) *FileChangedResult

ParseFileChangedResult extracts the structured return value from an onFileChanged hook result. Returns nil for nil, non-map, or maps without recognized keys (issue #1100).

type HookAssetPayload

type HookAssetPayload struct {
	Path    string `json:"path"`
	Content string `json:"content"`
}

HookAssetPayload is the outbound payload for per-asset onAssetProcess dispatch. Sent once per asset file with the relative path and file content as a string. Return value's "content" key replaces the asset content written to the output directory.

type HookBuildCompletePayload added in v0.6.0

type HookBuildCompletePayload struct {
	PageCount int      `json:"pageCount"`
	Duration  string   `json:"duration"`
	Errors    []string `json:"errors"`
	OutputDir string   `json:"outputDir"`
}

HookBuildCompletePayload is the trimmed onBuildComplete payload sent to plugins. Only includes stats + outputDir — no rendered HTML, cache, or site data (issue #1098).

type HookCascadePayload

type HookCascadePayload struct {
	Path string                 `json:"path"`
	Data map[string]interface{} `json:"data"`
}

HookCascadePayload is one entry in the onDataCascadeReady batch payload.

type HookDetailer

type HookDetailer interface {
	RegisteredHookDetails() []HookRegistration
}

HookDetailer is implemented by runtimes that can report hook priorities. Runtimes without priority support fall back to RegisteredHooks() with default priority 50.

type HookFormatRenderedPayload added in v0.6.0

type HookFormatRenderedPayload struct {
	Format      string                 `json:"format"`
	Content     string                 `json:"content"`
	URL         string                 `json:"url"`
	Path        string                 `json:"path"`
	FrontMatter map[string]interface{} `json:"frontMatter"`
}

HookFormatRenderedPayload is the outbound payload for onFormatRendered (per-format body). Only the returned content field is applied back; format, frontMatter, url, and path are read-only context for conditional processing (issue #1102).

type HookFunc

type HookFunc func(ctx context.Context, payload interface{}) (interface{}, error)

HookFunc processes a hook payload and returns a (potentially modified) result. The context carries the per-hook timeout deadline for cooperative cancellation.

type HookName

type HookName string

HookName identifies a lifecycle event.

const (
	OnConfig             HookName = "onConfig"
	OnBeforeValidation   HookName = "onBeforeValidation"
	OnAfterValidation    HookName = "onAfterValidation"
	OnDataFetched        HookName = "onDataFetched"
	OnDataCascadeReady   HookName = "onDataCascadeReady"
	OnPagesReady         HookName = "onPagesReady"
	OnContentLoaded      HookName = "onContentLoaded"
	OnContentTransformed HookName = "onContentTransformed"
	OnPageRendered       HookName = "onPageRendered"
	OnFormatRendered     HookName = "onFormatRendered"
	OnAssetProcess       HookName = "onAssetProcess"
	OnBuildComplete      HookName = "onBuildComplete"
	OnDevServerStart     HookName = "onDevServerStart"
	OnFileChanged        HookName = "onFileChanged"
)

type HookPagePayload

type HookPagePayload struct {
	Path        string                 `json:"path"`
	URL         string                 `json:"url"`
	FrontMatter map[string]interface{} `json:"frontMatter"`
	Content     string                 `json:"content,omitempty"`
	HTML        string                 `json:"html,omitempty"`
}

HookPagePayload is the outbound representation of a page sent to plugins. Separate from the template data path (which uses map[string]interface{} for liquidgo).

type HookPagesReadyPayload

type HookPagesReadyPayload struct {
	Pages    []HookPagePayload      `json:"pages"`
	SiteData map[string]interface{} `json:"siteData"`
}

HookPagesReadyPayload is the outbound payload for onPagesReady (per-batch).

type HookRegistration

type HookRegistration struct {
	Name     string
	Priority int
	Scope    *HookScope
}

HookRegistration pairs a hook name with its priority and optional scope.

type HookRegistry

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

HookRegistry manages lifecycle hook registrations and execution.

func NewHookRegistry

func NewHookRegistry() *HookRegistry

NewHookRegistry creates an empty hook registry with a default timeout of 5000ms.

func (*HookRegistry) HasHooks

func (r *HookRegistry) HasHooks(event HookName) bool

HasHooks returns true if any hooks are registered for the given event.

func (*HookRegistry) Register

func (r *HookRegistry) Register(event HookName, fn HookFunc)

Register adds a hook function for the given event with default priority (50).

func (*HookRegistry) RegisterBatchWithOptions

func (r *HookRegistry) RegisterBatchWithOptions(event HookName, singleFn HookFunc, batchFn BatchHookFunc, scope HookScope, priority int)

RegisterBatchWithOptions adds a batch-capable hook with scope and explicit priority.

func (*HookRegistry) RegisterBatchWithPriority

func (r *HookRegistry) RegisterBatchWithPriority(event HookName, fn HookFunc, batchFn BatchHookFunc, priority int)

RegisterBatchWithPriority adds a hook with both single and batch dispatch functions. The batch function is used by RunBatchWithTimeout to distribute work across workers.

func (*HookRegistry) RegisterWithOptions

func (r *HookRegistry) RegisterWithOptions(event HookName, fn HookFunc, scope HookScope, priority int)

RegisterWithOptions adds a hook with scope and explicit priority.

func (*HookRegistry) RegisterWithPriority

func (r *HookRegistry) RegisterWithPriority(event HookName, fn HookFunc, priority int)

RegisterWithPriority adds a hook function for the given event with explicit priority. Lower priority runs first. Hooks with the same priority preserve registration order.

func (*HookRegistry) Run

func (r *HookRegistry) Run(event HookName, payload interface{}) (interface{}, error)

Run executes all hooks for an event in priority order, chaining results. Context fields from the original payload are merged for chain carry-forward (issue #1216).

func (*HookRegistry) RunBatchWithProgress

func (r *HookRegistry) RunBatchWithProgress(event HookName, payloads []interface{}, onProgress BatchProgressFunc) ([]interface{}, error)

RunBatchWithProgress is like RunBatchWithTimeout but accepts a progress callback that fires after each item completes during batch hook execution. Context fields (url, path, frontMatter) from the original payloads are merged into hook results for chain carry-forward (issue #1216).

func (*HookRegistry) RunBatchWithTimeout

func (r *HookRegistry) RunBatchWithTimeout(event HookName, payloads []interface{}) ([]interface{}, error)

RunBatchWithTimeout dispatches multiple payloads through all hooks for an event. Hooks with a batchFn use batch dispatch (distributing across workers). Hooks without batchFn fall back to per-item dispatch with timeout enforcement. Batch timeout scales linearly with payload count (timeout × itemCount).

func (*HookRegistry) RunEachWithTimeout added in v0.5.0

func (r *HookRegistry) RunEachWithTimeout(event HookName,
	payloadFn func(i int, scope *HookScope) interface{},
	resultFn func(i int, scope *HookScope, result interface{}) error,
) error

RunEachWithTimeout runs each hook for an event individually with timeout enforcement. Before each hook, payloadFn builds the per-hook payload (receiving the hook index and scope). After each hook, resultFn processes the result. If resultFn returns an error, execution stops. Timed-out hooks are skipped with a warning (resultFn is not called).

func (*HookRegistry) RunWithTimeout

func (r *HookRegistry) RunWithTimeout(event HookName, payload interface{}) (interface{}, error)

RunWithTimeout executes all hooks for an event with timeout enforcement. If a hook exceeds the timeout, its modifications are discarded (the pre-hook payload is kept), a warning is logged, and the build continues. Each hook receives a context with the timeout deadline for cooperative cancellation. Context fields (url, path, frontMatter) from the original payload are merged into hook results for chain carry-forward (issue #1216).

func (*HookRegistry) ScopeFor

func (r *HookRegistry) ScopeFor(event HookName) []*HookScope

ScopeFor returns the scope for each hook registered on the event, in priority order. Returns nil when no hooks are registered. Entries are nil for unscoped hooks.

func (*HookRegistry) SetTimeout

func (r *HookRegistry) SetTimeout(ms int)

SetTimeout configures the per-hook execution timeout in milliseconds.

func (*HookRegistry) Timeout

func (r *HookRegistry) Timeout() int

Timeout returns the current per-hook timeout in milliseconds.

func (*HookRegistry) Warnings

func (r *HookRegistry) Warnings() []string

Warnings returns warnings from hook execution (e.g., timeouts) and plugin loading (e.g., duplicate registrations).

type HookRenderedPayload added in v0.6.0

type HookRenderedPayload struct {
	HTML        string                 `json:"html"`
	FrontMatter map[string]interface{} `json:"frontMatter"`
	URL         string                 `json:"url"`
	Path        string                 `json:"path"`
}

HookRenderedPayload is the outbound payload for onPageRendered (per-page). Only the returned html field is applied back; frontMatter, url, and path are read-only context for conditional processing (issue #1095).

type HookScope

type HookScope struct {
	Data       []string   `json:"data"` // siteData keys; nil = omit, ["*"] = all
	Pages      PagesScope // page filtering mode
	PageFields []string   `json:"pageFields"` // per-page fields; nil = all
}

HookScope declares what data subset a plugin hook needs.

func (*HookScope) WantsAllData

func (s *HookScope) WantsAllData() bool

WantsAllData returns true if Data contains "*".

func (*HookScope) WantsField

func (s *HookScope) WantsField(name string) bool

WantsField returns true if name is in PageFields, or PageFields is nil or contains "*".

type HookTransformPayload

type HookTransformPayload struct {
	Path        string                 `json:"path"`
	URL         string                 `json:"url"`
	FrontMatter map[string]interface{} `json:"frontMatter"`
	HTML        string                 `json:"html"`
	TOC         []content.TOCEntry     `json:"toc,omitempty"`
}

HookTransformPayload is the outbound payload for onContentTransformed (per-page).

type Message

type Message struct {
	ID        int           `json:"id"`
	Type      string        `json:"type,omitempty"`      // "hook", "ssr", "filter"
	Name      string        `json:"name,omitempty"`      // hook/filter name
	Payload   interface{}   `json:"payload,omitempty"`   // hook/filter payload
	Result    interface{}   `json:"result,omitempty"`    // response result
	Error     string        `json:"error,omitempty"`     // error message from bridge
	Instances []SSRInstance `json:"instances,omitempty"` // SSR render instances
}

Message represents a JSON-RPC message exchanged between Alloy (Go) and the Node bridge subprocess. Framed with LSP-style Content-Length headers over stdin/stdout.

func DecodeMessage

func DecodeMessage(data []byte) (*Message, error)

DecodeMessage parses an LSP-style framed byte sequence back into a Message. Supports both single-header and split-body (multi-header) frames. Returns an error if the Content-Length header is missing or malformed.

type NodeBridge

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

NodeBridge manages the lifecycle of the Node subprocess used for Tier 3 plugins. Communication uses length-prefixed JSON-RPC over stdin/stdout.

func NewNodeBridge

func NewNodeBridge(projectRoot string) *NodeBridge

NewNodeBridge creates a Node bridge for the given project root.

func (*NodeBridge) PID

func (b *NodeBridge) PID() int

PID returns the process ID of the Node subprocess, or 0 if not running.

func (*NodeBridge) Send

func (b *NodeBridge) Send(msg *Message) (*Message, error)

Send sends a JSON-RPC message and reads the response. Supports both single-header and multi-header (split-body) responses.

func (*NodeBridge) Start

func (b *NodeBridge) Start() error

Start spawns the Node subprocess with the embedded bridge script. When a project root is available, the bridge script is written under .alloy/ so Node's module resolution can find node_modules/ via normal ancestor directory traversal.

func (*NodeBridge) State

func (b *NodeBridge) State() BridgeState

State returns the current lifecycle state of the bridge.

func (*NodeBridge) Stop

func (b *NodeBridge) Stop() error

Stop gracefully shuts down the Node subprocess and its process group.

func (*NodeBridge) WorkingDir

func (b *NodeBridge) WorkingDir() string

WorkingDir returns the working directory of the Node subprocess.

type NodeRuntime

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

NodeRuntime runs Tier 3 Node plugins via a persistent subprocess. Communicates via JSON-RPC over stdin/stdout using the embedded bridge.js.

func NewNodeRuntime

func NewNodeRuntime() *NodeRuntime

NewNodeRuntime creates a new Node.js plugin runtime with its own bridge. Defaults to the current working directory as the project root for module resolution.

func (*NodeRuntime) BatchCallHook

func (r *NodeRuntime) BatchCallHook(name string, payloads []interface{}, onProgress func(int)) ([]interface{}, error)

BatchCallHook distributes payloads across the worker pool for parallel processing. Uses per-page IPC dispatch which outperforms large batch JSON serialization.

func (*NodeRuntime) CallFilter

func (r *NodeRuntime) CallFilter(name string, input interface{}, args ...interface{}) (interface{}, error)

CallFilter routes a filter call through the Node subprocess.

func (*NodeRuntime) CallHook

func (r *NodeRuntime) CallHook(name string, payload interface{}) (interface{}, error)

CallHook routes a hook call through the Node subprocess.

func (*NodeRuntime) CallShortcode

func (r *NodeRuntime) CallShortcode(name string, args []string, innerContent string) (string, error)

CallShortcode routes a shortcode call through the Node subprocess.

func (*NodeRuntime) CallSource added in v0.5.0

func (r *NodeRuntime) CallSource(name string, config map[string]interface{}) (interface{}, error)

CallSource invokes a registered data source handler in the Node subprocess. Applies sourceTimeout (default 5s) to prevent slow handlers from hanging the build.

func (*NodeRuntime) Close

func (r *NodeRuntime) Close()

Close shuts down the worker pool and primary Node subprocess.

func (*NodeRuntime) CloseWorkers

func (r *NodeRuntime) CloseWorkers()

CloseWorkers shuts down all worker pool bridges.

func (*NodeRuntime) EvalFile

func (r *NodeRuntime) EvalFile(path string) error

EvalFile loads a JS plugin file in the Node subprocess via ESM import(). The absolute file path is sent to the bridge, which uses dynamic import() to load the plugin as a native ES module.

func (*NodeRuntime) EvalWarnings

func (r *NodeRuntime) EvalWarnings() []string

EvalWarnings returns warnings collected during EvalFile calls.

func (*NodeRuntime) PrepareWorkerPool

func (r *NodeRuntime) PrepareWorkerPool(n int) error

PrepareWorkerPool starts n-1 additional Node bridges for parallel hook dispatch. Each worker loads the same plugin files as the primary bridge. Skipped when the runtime has no hooks (only filters/shortcodes).

func (*NodeRuntime) ProjectRoot

func (r *NodeRuntime) ProjectRoot() string

ProjectRoot returns the project root used for Node module resolution.

func (*NodeRuntime) RegisteredFilters

func (r *NodeRuntime) RegisteredFilters() []string

RegisteredFilters returns the names of filters registered by the Node plugin.

func (*NodeRuntime) RegisteredHookDetails

func (r *NodeRuntime) RegisteredHookDetails() []HookRegistration

RegisteredHookDetails returns hook registrations with priority and scope.

func (*NodeRuntime) RegisteredHooks

func (r *NodeRuntime) RegisteredHooks() []string

RegisteredHooks returns the deduplicated names of hooks registered by the Node plugin.

func (*NodeRuntime) RegisteredShortcodes

func (r *NodeRuntime) RegisteredShortcodes() []string

RegisteredShortcodes returns the names of shortcodes registered by the Node plugin.

func (*NodeRuntime) RegisteredSources added in v0.5.0

func (r *NodeRuntime) RegisteredSources() []string

RegisteredSources returns the names of data sources registered by the Node plugin.

func (*NodeRuntime) Restart added in v0.6.0

func (r *NodeRuntime) Restart() error

Restart stops the Node bridge subprocess and worker pool, then starts a fresh bridge and re-evaluates all previously loaded plugin files. Used when onFileChanged returns restart: true — Node's ESM module cache holds stale references, so a fresh process is needed to re-import changed component definitions (issue #1100).

Restart re-sends eval messages but does not parse the responses to refresh filter/hook/shortcode registrations. This is safe because restart is for clearing ESM caches when imported dependencies change, not when the plugin's own registrations change. If plugin registrations change, a full rebuild (which creates fresh runtimes) is required.

Worker pools are not recreated — the dev server registry never has worker pools (PrepareWorkerPool is only called inside pipeline.Build on a separate registry). If future refactoring moves worker pool setup to the dev registry, this method would need updating.

func (*NodeRuntime) SetProjectRoot

func (r *NodeRuntime) SetProjectRoot(root string)

SetProjectRoot sets the project root used for Node module resolution.

func (*NodeRuntime) SetSiteData

func (r *NodeRuntime) SetSiteData(data map[string]interface{}) error

SetSiteData is a stub for the Node runtime. Site data injection over the Node bridge is not yet implemented — returns nil (no-op) since Node plugins receive data through hook payloads rather than a persistent alloy.data binding.

func (*NodeRuntime) SetSourceTimeout added in v0.5.0

func (r *NodeRuntime) SetSourceTimeout(d time.Duration)

SetSourceTimeout configures the timeout for source handler calls.

type PagesScope

type PagesScope struct {
	Mode       PagesScopeMode
	Glob       string              // path pattern when Mode == PagesScopeGlob
	Taxonomies map[string][]string // taxonomy → terms when Mode == PagesScopeTaxonomy
	Explicit   bool                // true when the plugin explicitly set a pages value
}

PagesScope controls which pages a hook receives.

type PagesScopeMode

type PagesScopeMode int

PagesScopeMode determines how pages are filtered for a hook.

const (
	PagesScopeNone     PagesScopeMode = iota // skip pages entirely
	PagesScopeAll                            // send all pages
	PagesScopeGlob                           // filter by path glob
	PagesScopeTaxonomy                       // filter by taxonomy terms
)

type PluginFilterRuntime

type PluginFilterRuntime interface {
	RegisteredFilters() []string
	CallFilter(name string, input interface{}, args ...interface{}) (interface{}, error)
	RegisteredShortcodes() []string
	CallShortcode(name string, args []string, innerContent string) (string, error)
	RegisteredHooks() []string
	// SetSiteData injects site data so plugins can access it (e.g. alloy.data in JS).
	// Implementations must treat nil as an empty map. Data values must be JSON-serializable.
	SetSiteData(data map[string]interface{}) error
}

PluginFilterRuntime is the interface for plugin runtimes that can provide filters, shortcodes, and hooks to the template engine and hook registry. QuickJSRuntime, WASMRuntime, and NodeRuntime all implement this interface.

type PluginInfo

type PluginInfo struct {
	Path    string        // File path relative to plugins dir
	Name    string        // Plugin name (filename without extension)
	Tier    PluginTier    // Execution tier
	Runtime PluginRuntime // Specific runtime within the tier
}

PluginInfo describes a discovered plugin file.

func ClassifyPlugin

func ClassifyPlugin(path string) (*PluginInfo, error)

ClassifyPlugin determines the tier and runtime for a plugin file based on its extension and (for .js/.ts files) whether it exports runtime: "node".

type PluginRuntime

type PluginRuntime string

PluginRuntime distinguishes sub-types within a tier.

const (
	RuntimeGoBuiltIn PluginRuntime = "go"
	RuntimeQuickJS   PluginRuntime = "quickjs"
	RuntimeWASM      PluginRuntime = "wasm"
	RuntimeNode      PluginRuntime = "node"
)

type PluginTier

type PluginTier int

PluginTier represents the execution tier of a plugin.

const (
	// TierBuiltIn is Tier 1: Go built-in filters compiled into the binary.
	TierBuiltIn PluginTier = iota + 1
	// TierInProcess is Tier 2: In-process plugins via wazero (QuickJS or WASM).
	TierInProcess
	// TierNode is Tier 3: Node subprocess plugins via IPC bridge.
	TierNode
)

type QuickJSRuntime

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

QuickJSRuntime wraps a QuickJS instance for Tier 2 in-process JS plugins. JavaScript is executed via QuickJS compiled to WASM, running on wazero (pure Go, zero CGo). See PLAN.md §5.

func NewQuickJSRuntime

func NewQuickJSRuntime() *QuickJSRuntime

NewQuickJSRuntime creates a new QuickJS runtime instance. Startup cost is ~10-50ms (one-time).

func (*QuickJSRuntime) BatchCallHook added in v0.6.0

func (r *QuickJSRuntime) BatchCallHook(name string, payloads []interface{}, onProgress func(int)) ([]interface{}, error)

BatchCallHook loops synchronously through payloads calling callHookLocked for each one (issue #1185). No per-item goroutine/channel/context overhead. onProgress is called with 1-based indices after each item completes.

func (*QuickJSRuntime) CallFilter

func (r *QuickJSRuntime) CallFilter(name string, input interface{}, args ...interface{}) (interface{}, error)

CallFilter calls a registered filter function by name with an input value. The filter function is invoked in the QuickJS VM and the result is converted back to a Go value.

func (*QuickJSRuntime) CallHook

func (r *QuickJSRuntime) CallHook(name string, payload interface{}) (interface{}, error)

CallHook invokes a registered hook function by name with a payload. The hook function is invoked in the QuickJS VM and the result is converted back to a Go value.

func (*QuickJSRuntime) CallShortcode

func (r *QuickJSRuntime) CallShortcode(name string, args []string, innerContent string) (string, error)

CallShortcode calls a registered shortcode function by name with args and inner content. The shortcode function is invoked in the QuickJS VM with an array of string arguments.

func (*QuickJSRuntime) Close

func (r *QuickJSRuntime) Close()

Close releases resources held by the QuickJS runtime. Acquires the mutex to wait for any in-flight WASM operations (e.g., from timed-out RunWithTimeout goroutines) to finish before freeing the runtime.

func (*QuickJSRuntime) EvalFile

func (r *QuickJSRuntime) EvalFile(path string) error

EvalFile evaluates a JavaScript file in the QuickJS context. Plugin files using "export default function(alloy) { ... }" module syntax are transformed to an IIFE that receives the global alloy object.

func (*QuickJSRuntime) EvalWarnings

func (r *QuickJSRuntime) EvalWarnings() []string

EvalWarnings returns warnings collected during plugin evaluation.

func (*QuickJSRuntime) Init

func (r *QuickJSRuntime) Init() error

Init initializes the QuickJS instance via wazero.

func (*QuickJSRuntime) IsInitialized

func (r *QuickJSRuntime) IsInitialized() bool

IsInitialized returns whether the runtime has been initialized.

func (*QuickJSRuntime) RegisteredFilters

func (r *QuickJSRuntime) RegisteredFilters() []string

RegisteredFilters returns the names of all filters registered in the QuickJS context.

func (*QuickJSRuntime) RegisteredHookDetails

func (r *QuickJSRuntime) RegisteredHookDetails() []HookRegistration

RegisteredHookDetails returns hook registrations with priority and scope info.

func (*QuickJSRuntime) RegisteredHooks

func (r *QuickJSRuntime) RegisteredHooks() []string

RegisteredHooks returns the names of all hooks registered in the QuickJS context.

func (*QuickJSRuntime) RegisteredShortcodes

func (r *QuickJSRuntime) RegisteredShortcodes() []string

RegisteredShortcodes returns the names of all shortcodes registered in the QuickJS context.

func (*QuickJSRuntime) SetSiteData

func (r *QuickJSRuntime) SetSiteData(data map[string]interface{}) error

SetSiteData makes site data available as alloy.data in the JS context. Data is JSON-serialized from Go and parsed in JS. The resulting object is frozen to prevent cross-plugin mutation.

type Registry

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

Registry manages plugin discovery and loading.

func NewRegistry

func NewRegistry(pluginsDir string) *Registry

NewRegistry creates a plugin registry for the given plugins directory.

func (*Registry) Close

func (r *Registry) Close()

Close releases resources held by all loaded runtimes and any pre-initialized runtimes that were never consumed by LoadPlugins. Also clears global plugin source handlers to prevent stale closures from referencing stopped NodeBridge instances during dev server rebuilds.

func (*Registry) ConflictWarnings

func (r *Registry) ConflictWarnings() []string

ConflictWarnings returns any name conflict warnings produced during plugin loading.

func (*Registry) DiscoverPlugins

func (r *Registry) DiscoverPlugins() error

DiscoverPlugins scans the plugins directory and loads plugins by file extension.

func (*Registry) HasFilter

func (r *Registry) HasFilter(name string) bool

HasFilter reports whether a filter with the given name has been registered.

func (*Registry) InitRuntimes

func (r *Registry) InitRuntimes() ([]PluginFilterRuntime, []string)

InitRuntimes concurrently initializes runtimes for all discovered plugins (Phase A). Runtimes are created and compiled but not evaluated — no filters or hooks are registered. Call LoadPlugins after to complete Phase B.

QuickJS and WASM plugins run in goroutines (CPU-bound compilation). Node plugins are initialized sequentially on the calling goroutine because subprocess spawn is I/O-bound with side effects.

func (*Registry) LoadPlugins

func (r *Registry) LoadPlugins(hooks *HookRegistry) []string

LoadPlugins loads all discovered plugins into the given HookRegistry. If InitRuntimes was called first, uses pre-initialized runtimes (Phase B only). Otherwise initializes and evaluates sequentially (both phases). Returns warnings for plugins that fail to load (non-fatal).

func (*Registry) Plugins

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

Plugins returns the list of discovered plugins after DiscoverPlugins is called.

func (*Registry) RegisterFilter

func (r *Registry) RegisterFilter(name, source string)

RegisterFilter records a filter registration and tracks name conflicts.

func (*Registry) RestartNodeRuntimes added in v0.6.0

func (r *Registry) RestartNodeRuntimes() error

RestartNodeRuntimes stops and restarts all Node bridge subprocesses so that ESM module caches are cleared. Called when onFileChanged returns restart: true — the plugin's import()ed dependencies have changed on disk and the Node process must re-import them (issue #1100).

func (*Registry) Runtimes

func (r *Registry) Runtimes() []PluginFilterRuntime

Runtimes returns all loaded plugin runtimes for filter/shortcode bridging.

func (*Registry) SetPluginsDirRel added in v0.3.1

func (r *Registry) SetPluginsDirRel(rel string)

SetPluginsDirRel sets the config-relative plugins directory path used for filter source attribution (e.g. "plugins" or "tools/plugins").

func (*Registry) SetProjectRoot added in v0.3.1

func (r *Registry) SetProjectRoot(root string)

SetProjectRoot sets the project root directory for plugin runtimes.

func (*Registry) SetWASMCacheDir

func (r *Registry) SetWASMCacheDir(dir string)

SetWASMCacheDir configures a persistent compilation cache directory for WASM modules. When set, compiled native code is reused across builds. Creates the cache eagerly so it can be shared across all WASM runtimes.

type SSRInstance

type SSRInstance struct {
	Hash string `json:"hash"`
	HTML string `json:"html"`
}

SSRInstance represents a single component instance for SSR rendering.

type SandboxViolationError

type SandboxViolationError struct {
	Resource string // "filesystem", "network", etc.
	Detail   string
}

SandboxViolationError represents an attempt to access a forbidden resource.

func (*SandboxViolationError) Error

func (e *SandboxViolationError) Error() string

type WASMRuntime

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

WASMRuntime wraps a wazero WASM module for Tier 2 compiled plugins.

func NewWASMRuntime

func NewWASMRuntime() *WASMRuntime

NewWASMRuntime creates a new WASM runtime via wazero.

func (*WASMRuntime) CallExport

func (r *WASMRuntime) CallExport(name string, args ...interface{}) (interface{}, error)

CallExport calls an exported WASM function by name. At least one argument is required. For string arguments, the input is written to the module's memory and the function is called with (ptr, len). The result is read back from a packed i64 return.

func (*WASMRuntime) CallExportRaw

func (r *WASMRuntime) CallExportRaw(name string, ptr, length uint32) (string, error)

CallExportRaw invokes a WASM function with raw i32 arguments and reads the result from memory. The function must return a packed i64: result = (ptr << 32) | len. Returns error if the unpacked result is (0, 0) per the ABI error convention.

func (*WASMRuntime) CallFilter

func (r *WASMRuntime) CallFilter(name string, input interface{}, args ...interface{}) (interface{}, error)

CallFilter calls a WASM-exported filter function by name.

func (*WASMRuntime) CallHook

func (r *WASMRuntime) CallHook(name string, payload interface{}) (interface{}, error)

CallHook marshals a JSON envelope and dispatches to the hook(ptr, len) export. The envelope is {event: name, payload: data}. When the WASM module returns an envelope-shaped response (has "payload" key), the payload is extracted so callers receive the hook result directly, not the transport envelope.

func (*WASMRuntime) CallShortcode

func (r *WASMRuntime) CallShortcode(name string, args []string, innerContent string) (string, error)

CallShortcode is a no-op for WASM modules.

func (*WASMRuntime) Close

func (r *WASMRuntime) Close()

Close releases wazero resources.

func (*WASMRuntime) HasExport

func (r *WASMRuntime) HasExport(name string) bool

HasExport checks if the WASM module exports a function with the given name.

func (*WASMRuntime) LoadModule

func (r *WASMRuntime) LoadModule(path string) error

LoadModule loads a WASM module from the given file path. Validates the binary, compiles it, and discovers exported functions.

func (*WASMRuntime) RegisteredFilters

func (r *WASMRuntime) RegisteredFilters() []string

RegisteredFilters returns the names of exported functions that can be used as filters. Excludes well-known WASM runtime exports (memory, _start, etc.).

func (*WASMRuntime) RegisteredHookDetails

func (r *WASMRuntime) RegisteredHookDetails() []HookRegistration

RegisteredHookDetails returns hook registrations with per-hook priority and scope.

func (*WASMRuntime) RegisteredHooks

func (r *WASMRuntime) RegisteredHooks() []string

RegisteredHooks returns hook names discovered from the hooks() export.

func (*WASMRuntime) RegisteredShortcodes

func (r *WASMRuntime) RegisteredShortcodes() []string

RegisteredShortcodes returns an empty list — WASM modules don't register shortcodes.

func (*WASMRuntime) SetCacheDir

func (r *WASMRuntime) SetCacheDir(dir string)

SetCacheDir configures a persistent compilation cache directory. When set, wazero persists compiled native code to disk so subsequent builds skip WASM recompilation. Must be called before LoadModule.

func (*WASMRuntime) SetCompilationCache

func (r *WASMRuntime) SetCompilationCache(cache wazero.CompilationCache)

SetCompilationCache sets a shared compilation cache owned by the caller. The cache is NOT closed by WASMRuntime — the caller manages its lifecycle.

func (*WASMRuntime) SetSiteData

func (r *WASMRuntime) SetSiteData(data map[string]interface{}) error

SetSiteData is a no-op for WASM modules — they don't have a JS context to inject site data into.

Jump to

Keyboard shortcuts

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