Documentation
¶
Overview ¶
Package runtime provides expression evaluation for computed expressions. Expressions are inline code spans starting with = that evaluate against source data. Example: `=count(tasks where done)` evaluates the count of done tasks.
Security Considerations ¶
Expression evaluation operates on data from configured sources (lvt-source). This has security implications that developers should be aware of:
Source Access: Expressions can access any data exposed by sources defined in the page frontmatter or site config. Ensure sources only expose data appropriate for the page's audience.
No Code Execution: Expressions use a restricted DSL (count, sum, avg, min, max) with where clauses. They cannot execute arbitrary code or access system resources.
Error Messages: Parse and evaluation errors are returned to the client and displayed in the UI. Error messages should not leak sensitive information. The escapeAttr function sanitizes error text for safe HTML attribute rendering.
Field Access: The case-insensitive field matching (getFieldValue) allows accessing fields regardless of casing. This is intentional for usability but means field names are not access-controlled within a source.
No Injection: The expression parser validates syntax before evaluation. Source names and field names must match alphanumeric patterns, preventing injection attacks through expression strings.
Package runtime provides in-process state handling for lvt-source blocks, replacing the previous plugin-based compilation approach.
Index ¶
- Variables
- func EvaluateExpressions(expressions map[string]string, ctx *EvalContext) map[string]*ExprResult
- type Arg
- type DefaultResolver
- type EvalContext
- type ExprResult
- type Expression
- type FuncExpr
- type GenericState
- func NewGenericState(name string, cfg config.SourceConfig, siteDir, currentFile string) (*GenericState, error)
- func NewGenericStateForComputed(name string, cfg config.SourceConfig, siteDir, currentFile string, ...) (*GenericState, error)
- func NewGenericStateWithMetadata(name string, cfg config.SourceConfig, siteDir, currentFile string, ...) (*GenericState, error)
- func (s *GenericState) Close() error
- func (s *GenericState) GetFilteredData() []map[string]interface{}
- func (s *GenericState) GetState() (json.RawMessage, error)
- func (s *GenericState) GetStateAsInterface() (interface{}, error)
- func (s *GenericState) HandleAction(action string, data map[string]interface{}) error
- func (s *GenericState) SetPageConfig(actions map[string]*config.Action, registry func(string) (source.Source, bool))
- type Store
- type WhereClause
Constants ¶
This section is empty.
Variables ¶
var TemplateFuncs = template.FuncMap{ "now": func() time.Time { return time.Now() }, "today": func() string { return time.Now().Format("2006-01-02") }, "timestamp": func() string { return time.Now().Format(time.RFC3339) }, "unix": func() int64 { return time.Now().Unix() }, "formatDate": formatDate, "add": func(a, b int) int { return a + b }, "sub": func(a, b int) int { return a - b }, }
TemplateFuncs provides template functions for action data processing. These are used to fill in dynamic values like timestamps and dates.
Functions ¶
func EvaluateExpressions ¶
func EvaluateExpressions(expressions map[string]string, ctx *EvalContext) map[string]*ExprResult
EvaluateExpressions evaluates a map of expression strings. Returns a map of expression ID to result.
Types ¶
type Arg ¶
type Arg struct {
Name string `json:"name"`
Label string `json:"label"`
Type string `json:"type"`
Description string `json:"description"`
Required bool `json:"required"`
Default string `json:"default,omitempty"`
Value string `json:"value,omitempty"`
}
Arg represents an exec source argument
type DefaultResolver ¶
type DefaultResolver struct {
// contains filtered or unexported fields
}
DefaultResolver resolves template expressions in default values. It supports time functions and operator identity.
func NewDefaultResolver ¶
func NewDefaultResolver(operator string) *DefaultResolver
NewDefaultResolver creates a new DefaultResolver with the given operator identity.
func (*DefaultResolver) Resolve ¶
func (r *DefaultResolver) Resolve(value string) (interface{}, error)
Resolve processes a string value, expanding any template expressions. If the value doesn't contain template syntax, it's returned unchanged.
func (*DefaultResolver) ResolveMap ¶
func (r *DefaultResolver) ResolveMap(data map[string]interface{}) (map[string]interface{}, error)
ResolveMap processes all string values in a map, expanding template expressions. This is used to process action data before writing.
type EvalContext ¶
type EvalContext struct {
// Sources maps source names to their data rows.
Sources map[string][]map[string]interface{}
}
EvalContext provides data sources for expression evaluation.
func NewEvalContext ¶
func NewEvalContext() *EvalContext
NewEvalContext creates a new evaluation context.
type ExprResult ¶
type ExprResult struct {
Value interface{}
Error string
}
ExprResult represents the result of expression evaluation.
func (*ExprResult) Render ¶
func (r *ExprResult) Render() string
Render returns an HTML representation of the result.
type Expression ¶
type Expression interface {
// Eval evaluates the expression against the given context.
Eval(ctx *EvalContext) (interface{}, error)
}
Expression represents a parsed computed expression.
func ParseExpr ¶
func ParseExpr(input string) (Expression, error)
ParseExpr parses an expression string into an evaluable Expression. Supported syntax:
- count(source) - count all rows
- count(source where field) - count rows where field is truthy
- count(source where field = value) - count rows where field equals value
- sum(source.field) - sum a numeric field
- avg(source.field) - average a numeric field
- min(source.field) - minimum value of a field
- max(source.field) - maximum value of a field
type FuncExpr ¶
type FuncExpr struct {
Name string // count, sum, avg, min, max
Source string // source name (e.g., "tasks")
Field string // field name for sum/avg/min/max (e.g., "amount")
Where *WhereClause // optional where filter
}
FuncExpr represents a function call expression.
func (*FuncExpr) Eval ¶
func (e *FuncExpr) Eval(ctx *EvalContext) (interface{}, error)
Eval evaluates the function expression.
type GenericState ¶
type GenericState struct {
// Common fields (JSON-serializable for templates)
Data []map[string]interface{} `json:"data"`
Error string `json:"error,omitempty"`
Errors map[string]string `json:"errors,omitempty"`
// Datatable field - used when source is rendered in a table element
Table *datatable.DataTable `json:"table,omitempty"`
// Cache metadata for UI display
CacheInfo *cache.CacheInfo `json:"cache_info,omitempty"`
// Inline edit state - tracks which row is being edited (empty = none)
EditingID string `json:"editingId,omitempty"`
// Exec-specific fields
Output string `json:"output,omitempty"`
Stderr string `json:"stderr,omitempty"`
Duration int64 `json:"duration,omitempty"`
Status string `json:"status,omitempty"`
Command string `json:"command,omitempty"`
Args []Arg `json:"args,omitempty"`
Executable string `json:"executable,omitempty"`
// contains filtered or unexported fields
}
GenericState holds runtime state for any source type. It replaces the code-generated State structs that were previously compiled as plugins.
func NewGenericState ¶
func NewGenericState(name string, cfg config.SourceConfig, siteDir, currentFile string) (*GenericState, error)
NewGenericState creates a new state for the given source configuration. This replaces the plugin compilation step - state is created directly in-process.
func NewGenericStateForComputed ¶
func NewGenericStateForComputed(name string, cfg config.SourceConfig, siteDir, currentFile string, metadata map[string]string, sourceLookup func(string) (source.Source, bool)) (*GenericState, error)
NewGenericStateForComputed creates a state for a computed source. sourceLookup is used to resolve the parent source by name. If nil, the parent is created from config using createSource.
func NewGenericStateWithMetadata ¶
func NewGenericStateWithMetadata(name string, cfg config.SourceConfig, siteDir, currentFile string, metadata map[string]string) (*GenericState, error)
NewGenericStateWithMetadata creates a new state with block metadata for datatable support. Metadata should include "lvt-element" ("table", "select", or "div") and "lvt-columns" for tables.
func (*GenericState) Close ¶
func (s *GenericState) Close() error
Close releases any resources held by the source.
func (*GenericState) GetFilteredData ¶
func (s *GenericState) GetFilteredData() []map[string]interface{}
GetFilteredData returns the data with the active filter applied. This is used by the template renderer to show filtered results. Note: This method must be called while holding at least a read lock, or from within a method that already holds the lock.
func (*GenericState) GetState ¶
func (s *GenericState) GetState() (json.RawMessage, error)
GetState returns the current state for template rendering. This replaces the RPC GetState() call.
func (*GenericState) GetStateAsInterface ¶
func (s *GenericState) GetStateAsInterface() (interface{}, error)
GetStateAsInterface returns the state as an interface{} for template rendering. This is used by the WebSocket handler to render templates.
func (*GenericState) HandleAction ¶
func (s *GenericState) HandleAction(action string, data map[string]interface{}) error
HandleAction dispatches an action to the appropriate handler. This replaces the reflection-based dispatch used in generated plugins.
func (*GenericState) SetPageConfig ¶
func (s *GenericState) SetPageConfig(actions map[string]*config.Action, registry func(string) (source.Source, bool))
SetPageConfig configures page-level settings for custom actions. actions is the map of custom actions declared in frontmatter. registry is a lookup function to find sources by name (for SQL actions).
type Store ¶
type Store interface {
HandleAction(action string, data map[string]interface{}) error
// Close releases resources. Optional - returns nil if not implemented.
Close() error
}
Store is the interface for state objects that can handle actions. All state types (GenericState for lvt-source) implement this interface.
type WhereClause ¶
type WhereClause struct {
Field string // field to filter on
Operator string // comparison operator: =, !=, <, >, <=, >=
Value interface{} // value to compare against
}
WhereClause represents a filter condition.